// File: /workspace/github_cpp_makefile_star2_O2/chfeder[P]turbulence_generator/TurbGen.cpp
// Function: main
int main(int argc, char * argv[])
{
    /// initialise MPI
#ifdef HAVE_MPI
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &NPE);
    MPI_Comm_rank(MPI_COMM_WORLD, &MyPE);
#endif

    /// Parse inputs
    vector<string> Arguments(argc);
    for (int i = 0; i < argc; i++) Arguments[i] = static_cast<string>(argv[i]);
    if (ParseInputs(Arguments) == -1)
    {
        if (MyPE==0 && verbose>0) cout<<endl<<ProgSign+"Error in ParseInputs(). Exiting."<<endl;
        HelpMe();
#ifdef HAVE_MPI
        MPI_Finalize();
#endif
        return -1;
    }

    if (MyPE==0 && verbose>1) cout<<ProgSign+"started..."<<endl;

#ifdef HAVE_MPI
    // stop on error in domain decomposition if we run with MPI and number cores is > number of grid cells in X
    if (NPE > N[X]) {
        if (MyPE==0 && verbose>0) cout<<ProgSign+"Error in domain decomposition: NPE must be <= N[X]"<<endl;
        MPI_Finalize();
        return -1;
    }
#endif

    long starttime = time(NULL);
    cout<<setprecision(9);

    // create TurbGen class object
    TurbGen tg = TurbGen(MyPE);
    tg.set_verbose(verbose);

    // initialise generator to return a single turbulent realisation based on input parameters
    tg.init_single_realisation(ndim, L, k_min, k_mid, k_max, spect_form, power_law_exp, power_law_exp_2, angles_exp, sol_weight, random_seed);

    // get the number of vector field components
    int ncmp = tg.get_number_of_components();

    // set dimensionality dependencies
    if ((int)ndim < 3) { N[Z] = 1; L[Z] = 1.0; } // 2D
    if ((int)ndim < 2) { N[Y] = 1; L[Y] = 1.0; } // 1D

    // define cell size of uniform grid
    double del[3];
    for (int d = 0; d < 3; d++) del[d] = L[d] / N[d];

    // always generate within [0,L], cell-centered; user can shift output to target physical location, if needed
    double pos_beg[3] = {0.0, 0.0, 0.0}, pos_end[3] = {0.0, 0.0, 0.0}; // start and end coordinates of output grid
    // parallelise along X (generalises to non-MPI case, where NPE=1 and MyPE=0)
    int divN_PE = ceil((double)N[X]/(double)NPE);
    int NPE_main = N[X] / divN_PE;
    int modN_PE = N[X] - NPE_main * divN_PE;
    double divL_PE = L[X] * (double)divN_PE / (double)N[X];
    double modL_PE = L[X] * (double)modN_PE / (double)N[X];
    int NPE_in_use = NPE_main; if (modN_PE > 0) NPE_in_use += 1;
    int NX = 0; // number of cells in X for MyPE (idle PEs get nothing, i.e., NX=0)
    if (MyPE==0 && verbose>1)
        cout<<ProgSign+"NPE_main, divN_PE, modN_PE, divL_PE, modL_PE = "<<NPE_main<<" "<<divN_PE<<" "<<modN_PE<<" "<<divL_PE<<" "<<modL_PE<<endl;
    // set pos_beg and pos_end
    for (int d = 0; d < 3; d++) {
        if (d==X) { // parallelised direction - x
            if (MyPE < NPE_main) { // equally distribute to NPE_main cores
                pos_beg[d] = MyPE*divL_PE + del[d]/2.0; // first cell coordinate (cell center)
                pos_end[d] = (MyPE+1)*divL_PE - del[d]/2.0; // last cell coordinate (cell center)
                NX = divN_PE;
            } else if (MyPE < NPE_in_use) { // last PE gets the rest (idle PEs get nothing, i.e., NX=0)
                pos_beg[d] = NPE_main*divL_PE + del[d]/2.0; // first cell coordinate (cell center)
                pos_end[d] = L[X] - del[d]/2.0; // last cell coordinate (cell center)
                NX = modN_PE;
            }
            if (verbose>1)
                cout<<ProgSign+"MyPE, pos_beg[X], pos_beg[X], NX = "<<MyPE<<" "<<pos_beg[X]<<" "<<pos_end[X]<<" "<<NX<<endl;
        } else { // non-parallelised direction(s)
            pos_beg[d] = del[d]/2.0; // first cell coordinate (cell center)
            pos_end[d] = L[d] - del[d]/2.0; // last cell coordinate (cell center)
        }
    }

#ifdef HAVE_MPI
    if (MyPE==0 && verbose>0) {
        cout<<ProgSign+"First "<<NPE_main<<" core(s) carry(ies) NX="<<divN_PE<<" cell(s) (each)."<<endl;
        if (modN_PE > 0) cout<<ProgSign+"Core #"<<NPE_main+1<<" carries NX="<<modN_PE<<" cell(s)."<<endl;
        if (NPE_in_use < NPE) cout<<ProgSign+"Warning: non-optimal load balancing; "<<NPE-NPE_in_use<<" core(s) remain(s) idle."<<endl;
    }
#endif

    // total number of output grid cells
    int N_out[3] = {NX, N[Y], N[Z]};
    long ntot = 1; for (int d = 0; d < 3; d++) ntot *= N_out[d];
    // output grid, which receives the turbulent field (up to ndim = 3)
    float * grid_out[3];
    // allocate
    for (int d = 0; d < ncmp; d++) grid_out[d] = new float[ntot];

    // call to return uniform grid(s) with ncmp components of the turbulent field at requested positions
    tg.get_turb_vector_unigrid(pos_beg, pos_end, N_out, grid_out);

    // compute mean and std of generated turbulent field and then re-normalise to mean=0 and std=1
    double mean [3] = {0.0, 0.0, 0.0};
    double mean2[3] = {0.0, 0.0, 0.0};
    double std[3] = {0.0, 0.0, 0.0};
    for (int d = 0; d < ncmp; d++) {
        for (long ni = 0; ni < ntot; ni++) {
            mean [d] += grid_out[d][ni];
            mean2[d] += pow(grid_out[d][ni],2.0);
        }
    }
#ifdef HAVE_MPI
    MPI_Allreduce(MPI_IN_PLACE, mean , 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
    MPI_Allreduce(MPI_IN_PLACE, mean2, 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
#endif
    for (int d = 0; d < ncmp; d++) {
        mean [d] /= N[X]*N[Y]*N[Z]; // mean
        mean2[d] /= N[X]*N[Y]*N[Z]; // mean squared
        std[d] = sqrt(mean2[d] - mean[d]*mean[d]); // standard deviation
        for (long ni = 0; ni < ntot; ni++) {
            grid_out[d][ni] -= mean[d];
            grid_out[d][ni] /= std[d];
        }
    }

    // re-compute mean and std
    for (int d = 0; d < ncmp; d++) {
        mean[d] = 0.0; mean2[d] = 0.0;
        for (long ni = 0; ni < ntot; ni++) {
            mean [d] += grid_out[d][ni];
            mean2[d] += pow(grid_out[d][ni],2.0);
        }
    }
#ifdef HAVE_MPI
    MPI_Allreduce(MPI_IN_PLACE, mean , 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
    MPI_Allreduce(MPI_IN_PLACE, mean2, 3, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
#endif
    for (int d = 0; d < ncmp; d++) {
        mean [d] /= N[X]*N[Y]*N[Z]; // mean
        mean2[d] /= N[X]*N[Y]*N[Z]; // mean squared
        std[d] = sqrt(mean2[d] - mean[d]*mean[d]); // standard deviation
    }

    if (MyPE==0 && verbose>0) {
        cout<<ProgSign+"Generated "<<ndim<<"D turbulent field with"<<endl;
        cout<<ProgSign+" number of grid cells N ="; for (int d = 0; d < (int)ndim; d++) cout<<" "<<N[d]; cout<<endl;
        cout<<ProgSign+" physical size L ="; for (int d = 0; d < (int)ndim; d++) cout<<" "<<L[d]; cout<<endl;
        cout<<ProgSign+" mean (for each component) ="; for (int d = 0; d < ncmp; d++) cout<<" "<<mean[d]; cout<<endl;
        cout<<ProgSign+" 1D standard deviation (for each component) ="; for (int d = 0; d < ncmp; d++) cout<<" "<<std[d]; cout<<endl;
        string expected = "";
        if (ncmp==1) expected = "1";
        if (ncmp==2) expected = "sqrt(2)";
        if (ncmp==3) expected = "sqrt(3)";
        cout<<ProgSign+" total ("<<ndim<<"D) standard deviation (expected: "<<expected<<") = "<<sqrt(std[0]*std[0]+std[1]*std[1]+std[2]*std[2])<<endl;
    }

#ifdef HAVE_HDF5
    // write to HDF5 file
    if (MyPE==0 && verbose>0) {
        cout<<"-----------------------------------------------------"<<endl;
        cout<<ProgSign+"Creating '"<<outfilename<<"' for output..."<<endl;
    }
    HDFIO hdfio = HDFIO();
    hdfio.create(outfilename, MPI_COMM);
    // write scalars
    vector<int> hdf5dims(0);
    hdfio.write(&ndim, "ndim", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
    hdfio.write(&ncmp, "ncmp", hdf5dims, H5T_NATIVE_INT, MPI_COMM);
    hdfio.write(&k_min, "kmin", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
    hdfio.write(&k_mid, "kmid", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
    hdfio.write(&k_max, "kmax", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
    hdfio.write(&spect_form, "spect_form", hdf5dims, H5T_NATIVE_INT, MPI_COMM);
    if (spect_form == 2) {
        hdfio.write(&power_law_exp,   "power_law_exp",   hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
        hdfio.write(&power_law_exp_2, "power_law_exp_2", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
        hdfio.write(&angles_exp, "angles_exp", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
    }
    hdfio.write(&sol_weight, "sol_weight", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
    hdfio.write(&random_seed, "random_seed", hdf5dims, H5T_NATIVE_INT, MPI_COMM);
    // write N and L vectors
    hdf5dims.resize(1); hdf5dims[0] = (int)ndim;
    int No[(int)ndim]; double Lo[(int)ndim]; // order Z,Y,X
     for (int d = 0; d < (int)ndim; d++) {
        No[(int)ndim-1-d] = N[d];
        Lo[(int)ndim-1-d] = L[d];
    }
    hdfio.write(No, "N", hdf5dims, H5T_NATIVE_INT, MPI_COMM);
    hdfio.write(Lo, "L", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
    // write turbulent field (components)
    hdf5dims.resize((int)ndim); for (int d = 0; d < (int)ndim; d++) hdf5dims[(int)ndim-1-d] = N[d]; // order Z,Y,X
    if (MyPE==0 && verbose>1) { cout<<ProgSign+"hdf5dims ="; for (int d = 0; d < (int)ndim; d++) cout<<" "<<hdf5dims[d]; cout<<endl; }
    for (int dc = 0; dc < ncmp; dc++) { // loop over component(s)
        string dsetname = "turb_field";
        if (dc == 0) dsetname += "_x";
        if (dc == 1) dsetname += "_y";
        if (dc == 2) dsetname += "_z";
        hdfio.create_dataset(dsetname, hdf5dims, H5T_NATIVE_FLOAT, MPI_COMM); // create HDF5 dataset
        // specify dimensions and offset for slab operation
        hsize_t offset[(int)ndim], count[(int)ndim], out_offset[(int)ndim], out_count[(int)ndim];
        for (int d = 0; d < (int)ndim; d++) {
            int dd = (int)ndim-1-d; // order Z,Y,X
            // collective HDF5 IO only works if inactive cores participate, but with counts=0 and offsets=0
            offset[dd] = 0; count[dd] = 0; out_offset[dd] = 0; out_count[dd] = 0;
            if (MyPE < NPE_in_use) {
                if (d==0) offset[dd] = MyPE*divN_PE;
                count[dd] = N_out[d];
                out_offset[dd] = 0;
                out_count[dd] = N_out[d];
            }
        }
        if (verbose>1) {
            for (int d = 0; d < (int)ndim; d++)
                cout<<"MyPE, d, offset, count, out_offset, out_count = "<<
                        MyPE<<" "<<d<<" "<<offset[d]<<" "<<count[d]<<" "<<out_offset[d]<<" "<<out_count[d]<<endl;
        }
        // write slab to file (in parallel, if we have MPI)
        hdfio.overwrite_slab(grid_out[dc], dsetname, H5T_NATIVE_FLOAT, offset, count, (int)ndim, out_offset, out_count, MPI_COMM);
        if (MyPE==0 && verbose>0) cout<<ProgSign+"Dataset '"<<dsetname<<"' in '"<<outfilename<<"' written."<<endl;
    }
    // output generating modes and their amplitudes
    if (write_modes) {
        // modes
        vector< vector<double> > modes = tg.get_modes();
        int nmodes = modes[0].size(); // all dims have the same number of modes
        hdf5dims.resize(2); hdf5dims[0] = (int)ndim; hdf5dims[1] = nmodes;
        double * ptmp = new double[((int)ndim)*nmodes];
        for (int d = 0; d < (int)ndim; d++)
            for (int m = 0; m < nmodes; m++)
                ptmp[d*nmodes+m] = modes[d][m];
        hdfio.write(ptmp, "Fourier_modes", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
        delete [] ptmp;
        // amplitudes
        vector<double> amplitudes = tg.get_amplitudes();
        ptmp = new double[amplitudes.size()];
        for (int i = 0; i < amplitudes.size(); i++) ptmp[i] = amplitudes[i];
        hdf5dims.resize(1); hdf5dims[0] = amplitudes.size();
        hdfio.write(ptmp, "Fourier_amplitudes", hdf5dims, H5T_NATIVE_DOUBLE, MPI_COMM);
        delete [] ptmp;
    }
    hdfio.close();
    if (MyPE==0 && verbose>0) cout<<ProgSign+"Finished writing '"<<outfilename<<"'."<<endl;
#endif

    // clean up
    for (int d = 0; d < ncmp; d++) {
      if (grid_out[d]) delete [] grid_out[d]; grid_out[d] = NULL;
    }

    /// print out wallclock time used
    long endtime = time(NULL);
    long duration = endtime-starttime;
    if (verbose>1) cout<<ProgSign+"["<<MyPE<<"] Local runtime: "<<duration<<"s"<<endl;
#ifdef HAVE_MPI
    MPI_Allreduce(MPI_IN_PLACE, &duration, 1, MPI_LONG, MPI_MAX, MPI_COMM_WORLD);
#endif
    if (MyPE==0 && verbose>0) {
        cout<<"-----------------------------------------------------"<<endl;
        cout<<ProgSign+"Total runtime: "<<duration<<"s"<<endl;
    }

#ifdef HAVE_MPI
    MPI_Finalize();
#endif
    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x3f8, %rsp            # imm = 0x3F8
movq %rsi, %rbx
movslq %edi, %r14
leaq 0x150(%rsp), %rdi
leaq 0x1c0(%rsp), %r15
movq %r14, %rsi
movq %r15, %rdx
callq 0x3fc0
xorl %r13d, %r13d
testl %r14d, %r14d
cmovlel %r13d, %r14d
shlq $0x5, %r14
movq %rsp, %r12
cmpq %r13, %r14
je 0x25a7
movq (%rbx), %rsi
movq %r15, %rdi
movq %r12, %rdx
callq 0x3f84
movq 0x150(%rsp), %rdi
addq %r13, %rdi
movq %r15, %rsi
callq 0x2230
movq %r15, %rdi
callq 0x2398
addq $0x20, %r13
addq $0x8, %rbx
jmp 0x256f
leaq 0x168(%rsp), %rdi
leaq 0x150(%rsp), %rsi
callq 0x4012
leaq 0x168(%rsp), %rdi
callq 0x32fb
movl %eax, %ebx
leaq 0x168(%rsp), %rdi
callq 0x4066
movl 0x9ce6(%rip), %ecx      # 0xc2c4
movl 0x9bfc(%rip), %eax      # 0xc1e0
cmpl $-0x1, %ebx
je 0x2e1e
testl %ecx, %ecx
sete %cl
cmpl $0x2, %eax
setge %al
andb %cl, %al
cmpb $0x1, %al
jne 0x2642
leaq 0x9c7b(%rip), %rsi      # 0xc280
leaq 0x5af5(%rip), %rdx      # 0x8101
leaq 0x1c0(%rsp), %rdi
callq 0x4087
movq 0x99b8(%rip), %rdi      # 0xbfd8
leaq 0x1c0(%rsp), %rsi
callq 0x21b0
movq %rax, %rdi
callq 0x20c0
leaq 0x1c0(%rsp), %rdi
callq 0x2398
xorl %edi, %edi
callq 0x21c0
movq %rax, %r14
movq 0x9985(%rip), %rax      # 0xbfd8
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
movq $0x9, 0x8(%rax,%rcx)
movl 0x9c5b(%rip), %esi      # 0xc2c4
leaq 0x1c0(%rsp), %rdi
callq 0x40c0
movl 0x9b64(%rip), %eax      # 0xc1e0
leaq 0x1c0(%rsp), %rdi
movl %eax, (%rdi)
movsd 0x9b5a(%rip), %xmm0     # 0xc1e8
movsd 0x9b82(%rip), %xmm1     # 0xc218
movsd 0x9b8a(%rip), %xmm2     # 0xc228
movsd 0x9b7a(%rip), %xmm3     # 0xc220
movl 0x9b84(%rip), %edx      # 0xc230
movsd 0x9b84(%rip), %xmm4     # 0xc238
movsd 0x9b84(%rip), %xmm5     # 0xc240
movsd 0x9b84(%rip), %xmm6     # 0xc248
movsd 0x9b84(%rip), %xmm7     # 0xc250
movl 0x9b86(%rip), %ecx      # 0xc258
leaq 0x9b27(%rip), %rbx      # 0xc200
movq %rbx, %rsi
callq 0x41ec
cvttsd2si 0x9aff(%rip), %eax # 0xc1e8
cmpl $0x3, %eax
jge 0x271f
movl $0x1, 0x9b00(%rip)      # 0xc1f8
movabsq $0x3ff0000000000000, %rcx # imm = 0x3FF0000000000000
movq %rcx, 0x9b07(%rip)      # 0xc210
cmpl $0x2, %eax
je 0x271f
movl $0x1, 0x9adc(%rip)      # 0xc1f4
movq %rcx, 0x9ae9(%rip)      # 0xc208
movl 0x320(%rsp), %ebp
xorl %eax, %eax
leaq 0x9ac1(%rip), %r15      # 0xc1f0
cmpq $0xc, %rax
je 0x2756
movsd (%rbx), %xmm0
cvtsi2sdl (%rax,%r15), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x1a0(%rsp,%rax,2)
addq $0x4, %rax
addq $0x8, %rbx
jmp 0x272f
xorpd %xmm0, %xmm0
andq $0x0, 0x110(%rsp)
movapd %xmm0, 0x100(%rsp)
andq $0x0, 0xf0(%rsp)
movapd %xmm0, 0xe0(%rsp)
movl 0x9a6c(%rip), %ebx      # 0xc1f0
cvtsi2sd %ebx, %xmm0
movsd %xmm0, 0x28(%rsp)
cvtsi2sdl 0x9ac6(%rip), %xmm1 # 0xc25c
divsd %xmm1, %xmm0
callq 0x2040
cvttsd2si %xmm0, %ecx
movl %ebx, %eax
cltd
movl %ecx, 0x3c(%rsp)
idivl %ecx
movl %eax, 0x30(%rsp)
cvttpd2dq %xmm0, %xmm0
movsd 0x9a44(%rip), %xmm1     # 0xc200
cvtdq2pd %xmm0, %xmm0
movsd %xmm1, 0x40(%rsp)
mulsd %xmm1, %xmm0
divsd 0x28(%rsp), %xmm0
movapd %xmm0, 0x120(%rsp)
movl %edx, 0x24(%rsp)
testl %edx, %edx
setg %bl
cmpl $0x0, 0x9adb(%rip)      # 0xc2c4
jne 0x28c0
cmpl $0x1, 0x99ea(%rip)      # 0xc1e0
jle 0x28c0
leaq 0x9a7d(%rip), %rsi      # 0xc280
leaq 0x5902(%rip), %rdx      # 0x810c
movq %rsp, %rdi
callq 0x4087
movq 0x97bf(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movq %rax, %rdi
movl 0x30(%rsp), %esi
callq 0x2300
leaq 0x5a01(%rip), %rsi      # 0x8235
movq %rax, %rdi
callq 0x21f0
movq %rax, %rdi
movl 0x3c(%rsp), %esi
callq 0x2300
leaq 0x59e6(%rip), %rsi      # 0x8235
movq %rax, %rdi
callq 0x21f0
movq %rax, %rdi
movl 0x24(%rsp), %esi
callq 0x2300
leaq 0x59cb(%rip), %rsi      # 0x8235
movq %rax, %rdi
callq 0x21f0
movq %rax, %rdi
movapd 0x120(%rsp), %xmm0
callq 0x22c0
leaq 0x59ab(%rip), %rsi      # 0x8235
movq %rax, %rdi
callq 0x21f0
cvtsi2sdl 0x24(%rsp), %xmm1
movsd 0x40(%rsp), %xmm0
mulsd %xmm1, %xmm0
divsd 0x28(%rsp), %xmm0
movq %rax, %rdi
callq 0x22c0
movq %rax, %rdi
callq 0x20c0
movq %rsp, %rdi
callq 0x2398
movl %ebp, 0x4c(%rsp)
movq %r14, 0x138(%rsp)
xorl %ecx, %ecx
movb %bl, %cl
movl 0x30(%rsp), %eax
addl %eax, %ecx
movl %ecx, 0x40(%rsp)
cvtsi2sd %eax, %xmm0
movsd 0x1a0(%rsp), %xmm1
movsd 0x5719(%rip), %xmm2     # 0x8008
mulsd %xmm1, %xmm2
mulsd 0x120(%rsp), %xmm0
movsd %xmm2, 0x28(%rsp)
addsd %xmm2, %xmm0
movsd %xmm0, 0x140(%rsp)
mulsd 0x56f9(%rip), %xmm1     # 0x8010
movsd %xmm1, 0x148(%rsp)
xorl %r13d, %r13d
leaq 0x98d6(%rip), %r14      # 0xc200
movq %rsp, %rbx
leaq 0x5901(%rip), %r12      # 0x8235
xorl %ebp, %ebp
testq %r13, %r13
je 0x2979
cmpq $0x3, %r13
je 0x2aa3
movsd 0x1a0(%rsp,%r13,8), %xmm0
mulsd 0x56b1(%rip), %xmm0     # 0x8008
movsd %xmm0, 0x100(%rsp,%r13,8)
movsd (%r14), %xmm1
subsd %xmm0, %xmm1
movsd %xmm1, 0xe0(%rsp,%r13,8)
jmp 0x2a97
movl 0x9945(%rip), %eax      # 0xc2c4
cmpl 0x30(%rsp), %eax
jge 0x29c7
cvtsi2sd %eax, %xmm0
movapd 0x120(%rsp), %xmm1
mulsd %xmm1, %xmm0
addsd 0x28(%rsp), %xmm0
movsd %xmm0, 0x100(%rsp)
incl %eax
cvtsi2sd %eax, %xmm0
mulsd %xmm1, %xmm0
addsd 0x148(%rsp), %xmm0
movsd %xmm0, 0xe0(%rsp)
movl 0x3c(%rsp), %ebp
jmp 0x29fa
cmpl 0x40(%rsp), %eax
jge 0x29fa
movsd 0x140(%rsp), %xmm0
movsd %xmm0, 0x100(%rsp)
movsd 0x9819(%rip), %xmm0     # 0xc200
subsd 0x28(%rsp), %xmm0
movsd %xmm0, 0xe0(%rsp)
movl 0x24(%rsp), %ebp
cmpl $0x2, 0x97df(%rip)      # 0xc1e0
jl 0x2a97
movq %rbx, %rdi
leaq 0x986f(%rip), %rsi      # 0xc280
leaq 0x5724(%rip), %rdx      # 0x813c
callq 0x4087
movq 0x95b4(%rip), %rdi      # 0xbfd8
movq %rbx, %rsi
callq 0x21b0
movl 0x9892(%rip), %esi      # 0xc2c4
movq %rax, %rdi
callq 0x2300
movq %rax, %rdi
movq %r12, %rsi
callq 0x21f0
movsd 0x100(%rsp), %xmm0
movq %rax, %rdi
callq 0x22c0
movq %rax, %rdi
movq %r12, %rsi
callq 0x21f0
movsd 0xe0(%rsp), %xmm0
movq %rax, %rdi
callq 0x22c0
movq %rax, %rdi
movq %r12, %rsi
callq 0x21f0
movq %rax, %rdi
movl %ebp, %esi
callq 0x2300
movq %rax, %rdi
callq 0x20c0
movq %rbx, %rdi
callq 0x2398
incq %r13
addq $0x8, %r14
jmp 0x2936
movl %ebp, 0xb4(%rsp)
movq 0x9743(%rip), %rax      # 0xc1f4
movq %rax, 0xb8(%rsp)
pushq $0x1
popq %r14
xorl %eax, %eax
movl 0x4c(%rsp), %ebp
cmpq $0x3, %rax
je 0x2ada
movslq 0xb4(%rsp,%rax,4), %rcx
imulq %rcx, %r14
incq %rax
jmp 0x2ac3
movq %r14, %rax
shrq $0x3e, %rax
leaq (,%r14,4), %rcx
xorl %r13d, %r13d
negq %rax
movl $0x0, %ebx
sbbq %rbx, %rbx
orq %rcx, %rbx
testl %ebp, %ebp
movl $0x0, %r12d
cmovgl %ebp, %r12d
cmpq %r13, %r12
je 0x2b20
movq %rbx, %rdi
callq 0x2030
movq %rax, 0xc0(%rsp,%r13,8)
incq %r13
jmp 0x2b06
leaq 0x1c0(%rsp), %rdi
leaq 0x100(%rsp), %rsi
leaq 0xe0(%rsp), %rdx
leaq 0xb4(%rsp), %rcx
leaq 0xc0(%rsp), %r8
callq 0x45de
xorpd %xmm0, %xmm0
movapd %xmm0, 0x50(%rsp)
andq $0x0, 0x60(%rsp)
movapd %xmm0, 0x70(%rsp)
andq $0x0, 0x80(%rsp)
movapd %xmm0, 0x90(%rsp)
andq $0x0, 0xa0(%rsp)
xorl %eax, %eax
testq %r14, %r14
cmovleq %rax, %r14
cmpq %r12, %rax
je 0x2bca
xorl %ecx, %ecx
cmpq %rcx, %r14
je 0x2bc5
movq 0xc0(%rsp,%rax,8), %rdx
cvtss2sd (%rdx,%rcx,4), %xmm0
movsd 0x50(%rsp,%rax,8), %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, 0x50(%rsp,%rax,8)
mulsd %xmm0, %xmm0
addsd 0x70(%rsp,%rax,8), %xmm0
movsd %xmm0, 0x70(%rsp,%rax,8)
incq %rcx
jmp 0x2b8e
incq %rax
jmp 0x2b87
xorl %ebx, %ebx
xorpd %xmm2, %xmm2
cmpq %r12, %rbx
je 0x2c81
movl 0x9615(%rip), %eax      # 0xc1f4
imull 0x960a(%rip), %eax      # 0xc1f0
imull 0x960b(%rip), %eax      # 0xc1f8
cvtsi2sd %eax, %xmm1
movsd 0x50(%rsp,%rbx,8), %xmm3
divsd %xmm1, %xmm3
movsd %xmm3, 0x50(%rsp,%rbx,8)
movsd 0x70(%rsp,%rbx,8), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x70(%rsp,%rbx,8)
movapd %xmm3, %xmm1
mulsd %xmm3, %xmm1
subsd %xmm1, %xmm0
ucomisd %xmm2, %xmm0
jb 0x2c29
sqrtsd %xmm0, %xmm0
jmp 0x2c3e
movsd %xmm3, 0x30(%rsp)
callq 0x2170
movsd 0x30(%rsp), %xmm3
xorpd %xmm2, %xmm2
movsd %xmm0, 0x90(%rsp,%rbx,8)
xorl %eax, %eax
cmpq %rax, %r14
je 0x2c79
movq 0xc0(%rsp,%rbx,8), %rcx
cvtss2sd (%rcx,%rax,4), %xmm1
subsd %xmm3, %xmm1
cvtsd2ss %xmm1, %xmm1
cvtss2sd %xmm1, %xmm1
divsd %xmm0, %xmm1
cvtsd2ss %xmm1, %xmm1
movss %xmm1, (%rcx,%rax,4)
incq %rax
jmp 0x2c49
incq %rbx
jmp 0x2bd0
xorl %eax, %eax
cmpq %r12, %rax
je 0x2cd2
andq $0x0, 0x50(%rsp,%rax,8)
andq $0x0, 0x70(%rsp,%rax,8)
xorpd %xmm0, %xmm0
xorpd %xmm1, %xmm1
xorl %ecx, %ecx
cmpq %rcx, %r14
je 0x2ccd
movq 0xc0(%rsp,%rax,8), %rdx
cvtss2sd (%rdx,%rcx,4), %xmm2
addsd %xmm2, %xmm1
movsd %xmm1, 0x50(%rsp,%rax,8)
mulsd %xmm2, %xmm2
addsd %xmm2, %xmm0
movsd %xmm0, 0x70(%rsp,%rax,8)
incq %rcx
jmp 0x2c9e
incq %rax
jmp 0x2c83
xorl %ebx, %ebx
xorpd %xmm3, %xmm3
cmpq %rbx, %r12
je 0x2d40
movl 0x9511(%rip), %eax      # 0xc1f4
imull 0x9506(%rip), %eax      # 0xc1f0
imull 0x9507(%rip), %eax      # 0xc1f8
cvtsi2sd %eax, %xmm1
movsd 0x50(%rsp,%rbx,8), %xmm2
divsd %xmm1, %xmm2
movsd %xmm2, 0x50(%rsp,%rbx,8)
movsd 0x70(%rsp,%rbx,8), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x70(%rsp,%rbx,8)
mulsd %xmm2, %xmm2
subsd %xmm2, %xmm0
ucomisd %xmm3, %xmm0
jb 0x2d29
sqrtsd %xmm0, %xmm0
jmp 0x2d32
callq 0x2170
xorpd %xmm3, %xmm3
movsd %xmm0, 0x90(%rsp,%rbx,8)
incq %rbx
jmp 0x2cd8
cmpl $0x0, 0x957d(%rip)      # 0xc2c4
jne 0x30ec
cmpl $0x0, 0x948c(%rip)      # 0xc1e0
jle 0x30ec
leaq 0x951f(%rip), %rsi      # 0xc280
leaq 0x53f8(%rip), %rdx      # 0x8160
movq %rsp, %rdi
callq 0x4087
movq 0x9261(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movsd 0x9461(%rip), %xmm0     # 0xc1e8
movq %rax, %rdi
callq 0x22c0
leaq 0x53d5(%rip), %rsi      # 0x816b
movq %rax, %rdi
callq 0x21f0
movq %rax, %rdi
callq 0x20c0
movq %rsp, %rdi
callq 0x2398
leaq 0x94cb(%rip), %rsi      # 0xc280
leaq 0x53c6(%rip), %rdx      # 0x8182
movq %rsp, %rdi
callq 0x4087
movq 0x920d(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movq %rsp, %rdi
callq 0x2398
xorl %r13d, %r13d
movq 0x91f3(%rip), %rbx      # 0xbfd8
leaq 0x5449(%rip), %r14      # 0x8235
cvttsd2si 0x93f4(%rip), %eax # 0xc1e8
cltq
cmpq %rax, %r13
jge 0x2e8a
movq %rbx, %rdi
movq %r14, %rsi
callq 0x21f0
movl (%r15), %esi
movq %rax, %rdi
callq 0x2300
incq %r13
addq $0x4, %r15
jmp 0x2dec
testl %ecx, %ecx
sete %cl
testl %eax, %eax
setg %al
andb %cl, %al
cmpb $0x1, %al
jne 0x2e7d
movq 0x91a3(%rip), %rdi      # 0xbfd8
callq 0x20c0
movq %rax, %rbx
leaq 0x943c(%rip), %rsi      # 0xc280
leaq 0x5295(%rip), %rdx      # 0x80e0
leaq 0x1c0(%rsp), %rdi
callq 0x4087
leaq 0x1c0(%rsp), %rsi
movq %rbx, %rdi
callq 0x21b0
movq %rax, %rdi
callq 0x20c0
leaq 0x1c0(%rsp), %rdi
callq 0x2398
callq 0x3d12
pushq $-0x1
popq %rbx
jmp 0x3228
movq 0x9147(%rip), %rdi      # 0xbfd8
callq 0x20c0
leaq 0x93e3(%rip), %rsi      # 0xc280
leaq 0x52f8(%rip), %rdx      # 0x819c
movq %rsp, %rdi
callq 0x4087
movq 0x9125(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movq %rsp, %rdi
callq 0x2398
leaq 0x9336(%rip), %r15      # 0xc200
xorl %r13d, %r13d
movq 0x9104(%rip), %rbx      # 0xbfd8
leaq 0x535a(%rip), %r14      # 0x8235
cvttsd2si 0x9305(%rip), %eax # 0xc1e8
cltq
cmpq %rax, %r13
jge 0x2f0b
movq %rbx, %rdi
movq %r14, %rsi
callq 0x21f0
movsd (%r15), %xmm0
movq %rax, %rdi
callq 0x22c0
incq %r13
addq $0x8, %r15
jmp 0x2edb
movq 0x90c6(%rip), %rdi      # 0xbfd8
callq 0x20c0
leaq 0x9362(%rip), %rsi      # 0xc280
leaq 0x528a(%rip), %rdx      # 0x81af
movq %rsp, %rdi
callq 0x4087
movq 0x90a4(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movq %rsp, %rdi
callq 0x2398
xorl %r15d, %r15d
movq 0x908a(%rip), %rbx      # 0xbfd8
leaq 0x52e0(%rip), %r14      # 0x8235
cmpq %r15, %r12
je 0x2f79
movq %rbx, %rdi
movq %r14, %rsi
callq 0x21f0
movsd 0x50(%rsp,%r15,8), %xmm0
movq %rax, %rdi
callq 0x22c0
incq %r15
jmp 0x2f55
movq 0x9058(%rip), %rdi      # 0xbfd8
callq 0x20c0
leaq 0x92f4(%rip), %rsi      # 0xc280
leaq 0x5239(%rip), %rdx      # 0x81cc
movq %rsp, %rdi
callq 0x4087
movq 0x9036(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movq %rsp, %rdi
callq 0x2398
xorl %r15d, %r15d
movq 0x901c(%rip), %rbx      # 0xbfd8
leaq 0x5272(%rip), %r14      # 0x8235
cmpq %r15, %r12
je 0x2fea
movq %rbx, %rdi
movq %r14, %rsi
callq 0x21f0
movsd 0x90(%rsp,%r15,8), %xmm0
movq %rax, %rdi
callq 0x22c0
incq %r15
jmp 0x2fc3
movq 0x8fe7(%rip), %rdi      # 0xbfd8
callq 0x20c0
leaq 0x5f9d(%rip), %rsi      # 0x8f9a
movq %rsp, %rdi
leaq 0x180(%rsp), %rdx
callq 0x3f84
decl %ebp
cmpl $0x3, %ebp
jae 0x302c
movl %ebp, %eax
leaq 0x63eb(%rip), %rcx      # 0x9408
movslq (%rcx,%rax,4), %rsi
addq %rcx, %rsi
movq %rsp, %rdi
callq 0x2370
leaq 0x924d(%rip), %rsi      # 0xc280
leaq 0x51d2(%rip), %rdx      # 0x820c
leaq 0x180(%rsp), %rdi
callq 0x4087
movq 0x8f8a(%rip), %rdi      # 0xbfd8
leaq 0x180(%rsp), %rsi
callq 0x21b0
movsd 0x9185(%rip), %xmm0     # 0xc1e8
movq %rax, %rdi
callq 0x22c0
leaq 0x51a3(%rip), %rsi      # 0x8215
movq %rax, %rdi
callq 0x21f0
movq %rsp, %rsi
movq %rax, %rdi
callq 0x21b0
leaq 0x51ab(%rip), %rsi      # 0x8237
movq %rax, %rdi
callq 0x21f0
movsd 0x90(%rsp), %xmm0
movsd 0x98(%rsp), %xmm1
mulsd %xmm1, %xmm1
mulsd %xmm0, %xmm0
addsd %xmm1, %xmm0
movsd 0xa0(%rsp), %xmm1
mulsd %xmm1, %xmm1
addsd %xmm0, %xmm1
sqrtsd %xmm1, %xmm0
movq %rax, %rdi
callq 0x22c0
movq %rax, %rdi
callq 0x20c0
leaq 0x180(%rsp), %rdi
callq 0x2398
movq %rsp, %rdi
callq 0x2398
xorl %ebx, %ebx
cmpq %rbx, %r12
je 0x3113
movq 0xc0(%rsp,%rbx,8), %rdi
testq %rdi, %rdi
je 0x3105
callq 0x2250
andq $0x0, 0xc0(%rsp,%rbx,8)
incq %rbx
jmp 0x30ee
xorl %edi, %edi
callq 0x21c0
movq %rax, %rbx
subq 0x138(%rsp), %rbx
movl 0x90b5(%rip), %eax      # 0xc1e0
cmpl $0x1, %eax
jle 0x31a2
leaq 0x9149(%rip), %rsi      # 0xc280
leaq 0x50fe(%rip), %rdx      # 0x823c
movq %rsp, %rdi
callq 0x4087
movq 0x8e8b(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movl 0x9169(%rip), %esi      # 0xc2c4
movq %rax, %rdi
callq 0x2300
leaq 0x50d4(%rip), %rsi      # 0x823e
movq %rax, %rdi
callq 0x21f0
movq %rax, %rdi
movq %rbx, %rsi
callq 0x21d0
leaq 0x5ac5(%rip), %rsi      # 0x8c49
movq %rax, %rdi
callq 0x21f0
movq %rax, %rdi
callq 0x20c0
movq %rsp, %rdi
callq 0x2398
movl 0x903e(%rip), %eax      # 0xc1e0
cmpl $0x0, 0x911b(%rip)      # 0xc2c4
jne 0x3219
testl %eax, %eax
jle 0x3219
movq 0x8e22(%rip), %rdi      # 0xbfd8
leaq 0x5093(%rip), %rsi      # 0x8250
callq 0x21f0
movq %rax, %rdi
callq 0x20c0
leaq 0x90af(%rip), %rsi      # 0xc280
leaq 0x50ae(%rip), %rdx      # 0x8286
movq %rsp, %rdi
callq 0x4087
movq 0x8df1(%rip), %rdi      # 0xbfd8
movq %rsp, %rsi
callq 0x21b0
movq %rax, %rdi
movq %rbx, %rsi
callq 0x21d0
leaq 0x5a48(%rip), %rsi      # 0x8c49
movq %rax, %rdi
callq 0x21f0
movq %rax, %rdi
callq 0x20c0
movq %rsp, %rdi
callq 0x2398
leaq 0x1c0(%rsp), %rdi
callq 0x5198
xorl %ebx, %ebx
leaq 0x150(%rsp), %rdi
callq 0x4066
movl %ebx, %eax
addq $0x3f8, %rsp            # imm = 0x3F8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x32ce
jmp 0x32c9
jmp 0x32ce
jmp 0x32c4
jmp 0x32ce
jmp 0x32c4
jmp 0x32c4
jmp 0x32c4
jmp 0x32ce
jmp 0x32c4
jmp 0x32ce
jmp 0x32c4
jmp 0x32ce
jmp 0x32c4
jmp 0x32c4
jmp 0x32c4
jmp 0x32c9
jmp 0x3278
jmp 0x32c4
jmp 0x32c4
jmp 0x32c4
jmp 0x32c9
movq %rax, %rbx
leaq 0x1c0(%rsp), %rdi
callq 0x2398
jmp 0x32e6
movq %rax, %rbx
leaq 0x168(%rsp), %rdi
callq 0x4066
jmp 0x32e6
jmp 0x32c4
jmp 0x32ce
jmp 0x32ce
jmp 0x32c9
jmp 0x32ce
movq %rax, %rbx
leaq 0x180(%rsp), %rdi
callq 0x2398
jmp 0x32d1
jmp 0x32ce
jmp 0x32c4
jmp 0x32c4
jmp 0x32c4
jmp 0x32c4
jmp 0x32c4
movq %rax, %rbx
jmp 0x32d9
movq %rax, %rbx
jmp 0x32e6
movq %rax, %rbx
movq %rsp, %rdi
callq 0x2398
leaq 0x1c0(%rsp), %rdi
callq 0x5198
leaq 0x150(%rsp), %rdi
callq 0x4066
movq %rbx, %rdi
callq 0x2320