// File: /workspace/github_c_makefile_star2_O3/esheldon[P]xshear/src/shear.c
// Function: shear_procpair
void shear_procpair(Shear* self, 
                    Source* src, 
                    Lens* lens, 
                    Lensum* lensum) {

    ShearConfig* config=self->config;

    // make sure object is in a pair of unmasked adjacent
    // quadrants.  Using short-circuiting in if statement


    // checks against max radius
    int quadrant;
    double r_radians, posangle_radians;
    int keep=get_quad_info(lens, src,
                           &quadrant,
                           &r_radians,
                           &posangle_radians);

    if (!keep) {
        goto _procpair_bail;
    }

    if (config->mask_style == MASK_STYLE_EQ) {
        if (!quadeq_check_quadrant(lens->maskflags, quadrant)) {
            goto _procpair_bail;
        }
    } else if (config->mask_style == MASK_STYLE_SDSS) {
        if (!shear_test_quad_sdss(lens, src)) {
            goto _procpair_bail;
        }
    }

    double cos2pa = cos(2*posangle_radians);
    double sin2pa = sin(2*posangle_radians);


    // Philosophy:
    // Internal bookkeeping is the same, regardless of the input and intended output format.
    //
    // D=\sum_i(w_i*scinv_i^2*DeltaSigma_i)=\sum_i(w_i*scinv_i*g_i)
    // DeltaSigma=D/W where W=\sum_i(w_i*scinv_i^2) is a surface mass overdensity in physical units (Msol/Mpc^2)
    // g=D/S where S=\sum_i(w_i*scinv_i) is a unitless mean shear, weighted by (w_i*scinv_i)
    //
    // So we always output three columns: D, W=\sum_i(w_i*scinv_i^2) and S=\sum_i(w_i*scinv_i)
    //
    // We allow two different weighting style: config->weight_style=uniform and config->weight_style=optimal
    // 'optimal' will do what's written above, which maximizes the S/N
    // 'uniform' will use the weights w'_i = w_i/scinv_i; in that case, g is a unitless mean shear weighted by w_i 
    //           and DeltaSigma is still a (non-minimum variance) surface mass overdensity in physical units (Msol/Mpc^2)
    //
    // In the code below, we use the variable s for the weight on shear (i.e., D=\sum_i(s_i*g_i)).
    // In weight_style=optimal, s=w_i*scinv_i; in weight_style=uniform, s=w_i
    // 
    // The config->shear_units parameter controls the output format. "deltasig" and "shear" 
    // produce the backward-compatible output of D and W or, respectively, S
    // Output format "both" outputs both and also s_i and s_i*scinv_i-weighted sensitivities


    // (1) set sigma_crit^-1
    double scinv; // the sigma_crit^-1 that goes into S
    double zs;
    switch(config->scstyle) {
        case SIGMACRIT_STYLE_INTERP:
            scinv = interplin(src->zlens, src->scinv, lens->z);
            zs=-1.;
            break;
        case SIGMACRIT_STYLE_POINT:
            if ( (src->z - lens->z) < config->zdiff_min) {
                goto _procpair_bail;
            }
            double dcl = lens->da*(1.+lens->z);
            scinv = scinv_pre(lens->z, dcl, src->dc);
            zs=src->z;
            break;
        case SIGMACRIT_STYLE_SAMPLE:
            if(src->zs <= lens->z) {
                scinv=0.;
            } else {
                double dcl = lens->da*(1.+lens->z);
                scinv = scinv_pre(lens->z, dcl, src->dcs); // at sampled z of the source
            }
            zs=src->zs;
            break;
        default:
            fprintf(stderr, "unknown sigmacrit style %d\n", config->scstyle);
    }
    
    
    // (2) set shear weight s
    double s=src->weight;
    if(config->weight_style==WEIGHT_STYLE_OPTIMAL) {
        switch(config->scstyle) {
            case SIGMACRIT_STYLE_INTERP:
            case SIGMACRIT_STYLE_POINT:
                s *= scinv;
                break;
            case SIGMACRIT_STYLE_SAMPLE:
                if ( (src->z - lens->z) < config->zdiff_min) {
                    goto _procpair_bail;
                }
                double dcl = lens->da*(1.+lens->z);
                s *= scinv_pre(lens->z, dcl, src->dc); // src->dc is dc at the <z>, not the sampled z of the source
                break;
            default:
                fprintf(stderr, "unknown sigmacrit style %ld\n", config->scstyle);
        }
    }


    // (3) determine radius
    double r;
    if (config->r_units==UNITS_MPC) {
        // Mpc
        r = r_radians*lens->da;
    } else {
        // arcmin
        r = r_radians*R2D*60.;
    }

    double logr = log10(r);
    if (logr < config->log_rmin || logr > config->log_rmax) {
        goto _procpair_bail;
    }

    int rbin = (int)( (logr-config->log_rmin)/config->log_binsize );
    if (rbin < 0 || rbin >= config->nbin) {
        goto _procpair_bail;
    }

    // sign here depends on convention
    //double gt = -(src->g1*cos2pa + src->g2*sin2pa);
    //double gx =  (src->g1*sin2pa - src->g2*cos2pa);
    double gt = -(src->g1*cos2pa - src->g2*sin2pa);
    double gx =  (src->g1*sin2pa + src->g2*cos2pa);

    lensum->weight += s*scinv;
    lensum->totpairs += 1;
    
    lensum->npair[rbin] += 1;
    lensum->wsum[rbin] += s*scinv;
    lensum->ssum[rbin] += s;
    
    lensum->dsum[rbin] += s*gt;
    lensum->osum[rbin] += s*gx;

    lensum->rsum[rbin] += s*scinv*r;

    // sensitivity of gt/gx to shear in that direction
    double gsens_t=1.;
    double gsens_x=1.;

    if (config->shear_style==SHEAR_STYLE_LENSFIT) {
        // sensitivity of gt is
        // dgt/dgammat=-dg1/dgammat*cos2pa-dg2/dgammat*sin2pa
        //            =-dg1/dgamma1*dgamma1/dgammat*cos2pa-dg2/dgamma2*dgamma2/dgammat*sin2pa
        //            =g1sens*cos2pa^2+g2sens*sin2pa^2
    
        // the alternative is to just average them
        // double gsens = 0.5*(src->g1sens + src->g2sens); 
        // the only reason to not do that are strong-ish shears, where gsens is significantly
        // different along the tangential direction because tangential shears aren't small
        
        gsens_t=src->g1sens*cos2pa*cos2pa+src->g2sens*sin2pa*sin2pa;
        gsens_x=src->g1sens*sin2pa*sin2pa+src->g2sens*cos2pa*cos2pa;
    }
    
    // will have to implement something more complex here for metacal, maybe
        
    lensum->dsensum_w[rbin] += s*scinv*gsens_t;
    lensum->osensum_w[rbin] += s*scinv*gsens_x;
    lensum->dsensum_s[rbin] += s*gsens_t;
    lensum->osensum_s[rbin] += s*gsens_x;

    if(rbin<config->pairlog_rmax && rbin>=config->pairlog_rmin) {
      fprintf(config->pair_fd, "%ld %ld %d %le %le %le %le\n", lens->index, src->index, rbin, s, scinv, gsens_t, zs);
    }

_procpair_bail:

    return;

}

// Assembly:
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x58, %rsp
movsd 0x88(%rsi), %xmm5
movsd 0x90(%rsi), %xmm2
movsd 0x28(%rdx), %xmm0
movsd 0x30(%rdx), %xmm3
movapd %xmm5, %xmm1
mulsd %xmm0, %xmm1
movapd %xmm2, %xmm6
mulsd %xmm3, %xmm6
addsd %xmm1, %xmm6
movsd 0x40(%rdx), %xmm4
mulsd 0xa0(%rsi), %xmm4
movsd 0x38(%rdx), %xmm1
mulsd %xmm6, %xmm4
mulsd 0x98(%rsi), %xmm1
addsd %xmm4, %xmm1
movsd 0x58(%rdx), %xmm4
ucomisd %xmm1, %xmm4
ja 0x80a5
movq %rcx, %r15
movq %rdx, %r14
movq %rsi, %rbx
movsd %xmm6, 0x20(%rsp)
mulsd %xmm2, %xmm0
mulsd %xmm3, %xmm5
subsd %xmm0, %xmm5
movsd %xmm5, 0x8(%rsp)
movsd 0x318a(%rip), %xmm0     # 0xad88
ucomisd %xmm0, %xmm1
ja 0x7c1a
movsd 0x3174(%rip), %xmm2     # 0xad80
ucomisd %xmm1, %xmm2
movapd %xmm1, %xmm0
jbe 0x7c1a
movapd %xmm2, %xmm0
movq (%rdi), %r12
callq 0x2170
movsd 0x98(%rbx), %xmm2
mulsd 0x40(%r14), %xmm2
divsd 0xa0(%rbx), %xmm2
movsd %xmm0, 0x10(%rsp)
movsd 0x20(%rsp), %xmm1
mulsd 0x38(%r14), %xmm1
subsd %xmm2, %xmm1
movsd 0x8(%rsp), %xmm0
callq 0x2220
movapd %xmm0, %xmm1
addsd 0x3213(%rip), %xmm1     # 0xae78
movsd 0x32e3(%rip), %xmm0     # 0xaf50
movsd %xmm1, 0x8(%rsp)
mulsd %xmm1, %xmm0
movsd 0x32d9(%rip), %xmm1     # 0xaf58
ucomisd %xmm0, %xmm1
jbe 0x7c97
movsd 0x3233(%rip), %xmm2     # 0xaec0
addsd %xmm2, %xmm0
ucomisd %xmm0, %xmm1
ja 0x7c8d
ucomisd 0x32c1(%rip), %xmm0     # 0xaf60
jb 0x7cbb
movsd 0x32bf(%rip), %xmm1     # 0xaf68
movsd 0x32af(%rip), %xmm2     # 0xaf60
addsd %xmm1, %xmm0
ucomisd %xmm2, %xmm0
jae 0x7cb1
callq 0x9a9c
movl 0x1c(%r12), %ecx
cmpl $0x2, %ecx
je 0x7cdc
cmpl $0x3, %ecx
jne 0x7d25
movq 0x48(%r14), %rdi
movl %eax, %esi
callq 0x9ad2
jmp 0x7d1d
movq 0x48(%r14), %rdi
movsd 0x60(%r14), %xmm0
movsd 0x68(%r14), %xmm1
movsd 0x70(%r14), %xmm2
movsd 0x78(%r14), %xmm3
movsd 0xa8(%rbx), %xmm4
movsd 0xb0(%rbx), %xmm5
movsd 0xb8(%rbx), %xmm6
movsd 0xc0(%rbx), %xmm7
callq 0x9977
testl %eax, %eax
je 0x80a5
movsd 0x8(%rsp), %xmm0
addsd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
callq 0x2150
movapd %xmm0, 0x40(%rsp)
movsd 0x8(%rsp), %xmm0
callq 0x2260
movl 0x20(%r12), %edx
cmpl $0x1, %edx
movaps %xmm0, 0x20(%rsp)
je 0x7d8c
cmpl $0x3, %edx
je 0x7dd6
cmpl $0x2, %edx
jne 0x80b1
movq 0x58(%rbx), %rsi
movq 0x60(%rbx), %rdi
movsd 0x18(%r14), %xmm0
callq 0x9170
movapd %xmm0, %xmm2
movsd 0x2ff9(%rip), %xmm0     # 0xad80
jmp 0x7e19
movsd 0x68(%rbx), %xmm1
movsd 0x18(%r14), %xmm0
subsd %xmm0, %xmm1
movsd 0x98(%r12), %xmm2
ucomisd %xmm1, %xmm2
ja 0x80a5
movsd 0x2fd1(%rip), %xmm1     # 0xad88
addsd %xmm0, %xmm1
mulsd 0x20(%r14), %xmm1
movsd 0x70(%rbx), %xmm2
callq 0x6e9c
movapd %xmm0, %xmm2
movsd 0x68(%rbx), %xmm0
jmp 0x7e19
movsd 0x78(%rbx), %xmm1
movsd 0x18(%r14), %xmm0
xorpd %xmm2, %xmm2
movsd %xmm1, 0x18(%rsp)
ucomisd %xmm1, %xmm0
jae 0x7e1f
movsd 0x2f8f(%rip), %xmm1     # 0xad88
addsd %xmm0, %xmm1
mulsd 0x20(%r14), %xmm1
movsd 0x80(%rbx), %xmm2
callq 0x6e9c
movapd %xmm0, %xmm2
movsd 0x78(%rbx), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x48(%rbx), %xmm1
cmpl $0x1, 0x28(%r12)
movsd %xmm2, 0x38(%rsp)
jne 0x7ea3
movl 0x20(%r12), %edx
leal -0x1(%rdx), %eax
cmpl $0x2, %eax
movsd 0x10(%rsp), %xmm0
jae 0x7e4b
mulsd %xmm2, %xmm1
jmp 0x7ea9
movsd %xmm1, 0x8(%rsp)
cmpl $0x3, %edx
jne 0x80ff
movsd 0x68(%rbx), %xmm1
movsd 0x18(%r14), %xmm0
subsd %xmm0, %xmm1
movsd 0x98(%r12), %xmm2
ucomisd %xmm1, %xmm2
ja 0x80a5
movsd 0x2f03(%rip), %xmm1     # 0xad88
addsd %xmm0, %xmm1
mulsd 0x20(%r14), %xmm1
movsd 0x70(%rbx), %xmm2
callq 0x6e9c
movsd 0x8(%rsp), %xmm1
mulsd %xmm0, %xmm1
movsd 0x10(%rsp), %xmm0
movsd %xmm1, 0x8(%rsp)
cmpl $0x1, 0x48(%r12)
jne 0x7ebf
mulsd 0x20(%r14), %xmm0
jmp 0x7ecf
mulsd 0x3089(%rip), %xmm0     # 0xaf50
mulsd 0x30a1(%rip), %xmm0     # 0xaf70
movsd %xmm0, 0x10(%rsp)
callq 0x21a0
movsd 0x78(%r12), %xmm1
ucomisd %xmm0, %xmm1
ja 0x80a5
ucomisd 0x80(%r12), %xmm0
ja 0x80a5
subsd %xmm1, %xmm0
divsd 0x88(%r12), %xmm0
cvttsd2si %xmm0, %r8d
testl %r8d, %r8d
js 0x80a5
movl %r8d, %eax
cmpq %rax, 0x40(%r12)
jle 0x80a5
movsd 0x28(%rbx), %xmm1
movsd 0x30(%rbx), %xmm3
movapd 0x20(%rsp), %xmm5
movapd %xmm5, %xmm0
mulsd %xmm3, %xmm0
movapd %xmm1, %xmm2
movapd 0x40(%rsp), %xmm6
mulsd %xmm6, %xmm2
subsd %xmm0, %xmm2
movsd 0x8(%rsp), %xmm8
movapd %xmm8, %xmm0
movsd 0x38(%rsp), %xmm7
mulsd %xmm7, %xmm0
movsd 0x18(%r15), %xmm4
addsd %xmm0, %xmm4
movsd %xmm4, 0x18(%r15)
mulsd %xmm6, %xmm3
incq 0x20(%r15)
movq 0x30(%r15), %rcx
incq (%rcx,%rax,8)
mulsd %xmm5, %xmm1
addsd %xmm3, %xmm1
movq 0x40(%r15), %rcx
movsd (%rcx,%rax,8), %xmm3
addsd %xmm0, %xmm3
movsd %xmm3, (%rcx,%rax,8)
movq 0x48(%r15), %rcx
movsd (%rcx,%rax,8), %xmm3
addsd %xmm8, %xmm3
movsd %xmm3, (%rcx,%rax,8)
movq 0x50(%r15), %rcx
movsd (%rcx,%rax,8), %xmm3
mulsd %xmm8, %xmm2
subsd %xmm2, %xmm3
movsd %xmm3, (%rcx,%rax,8)
movq 0x58(%r15), %rcx
mulsd %xmm8, %xmm1
addsd (%rcx,%rax,8), %xmm1
movsd %xmm1, (%rcx,%rax,8)
movq 0x38(%r15), %rcx
movsd 0x10(%rsp), %xmm1
mulsd %xmm0, %xmm1
addsd (%rcx,%rax,8), %xmm1
movsd %xmm1, (%rcx,%rax,8)
cmpl $0x2, 0x18(%r12)
jne 0x8031
movapd %xmm7, %xmm1
unpcklpd %xmm6, %xmm5            # xmm5 = xmm5[0],xmm6[0]
movsd 0x38(%rbx), %xmm4
movsd 0x40(%rbx), %xmm2
unpcklpd %xmm4, %xmm4            # xmm4 = xmm4[0,0]
mulpd %xmm5, %xmm4
unpcklpd %xmm2, %xmm2            # xmm2 = xmm2[0,0]
mulpd %xmm5, %xmm2
mulpd %xmm5, %xmm2
shufpd $0x1, %xmm2, %xmm2      # xmm2 = xmm2[1,0]
mulpd %xmm5, %xmm4
addpd %xmm2, %xmm4
jmp 0x803d
movapd %xmm7, %xmm1
movapd 0x2da3(%rip), %xmm4     # 0xade0
movq 0x60(%r15), %rcx
movapd %xmm4, %xmm2
unpckhpd %xmm4, %xmm2            # xmm2 = xmm2[1],xmm4[1]
movapd %xmm0, %xmm3
mulsd %xmm2, %xmm3
addsd (%rcx,%rax,8), %xmm3
movsd %xmm3, (%rcx,%rax,8)
movq 0x68(%r15), %rcx
mulsd %xmm4, %xmm0
addsd (%rcx,%rax,8), %xmm0
movsd %xmm0, (%rcx,%rax,8)
movq 0x70(%r15), %rcx
movapd %xmm8, %xmm0
mulsd %xmm2, %xmm0
addsd (%rcx,%rax,8), %xmm0
movsd %xmm0, (%rcx,%rax,8)
movq 0x78(%r15), %rcx
mulsd %xmm8, %xmm4
addsd (%rcx,%rax,8), %xmm4
movsd %xmm4, (%rcx,%rax,8)
cmpq %rax, 0x50(%r12)
jle 0x80a5
cmpq %rax, 0x58(%r12)
jle 0x80ce
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
movq 0x7f40(%rip), %rax      # 0xfff8
movq (%rax), %rdi
leaq 0x2ff4(%rip), %rsi      # 0xb0b6
xorl %eax, %eax
callq 0x21b0
jmp 0x7e1f
movq 0x60(%r12), %rdi
movq (%r14), %rdx
movq 0x10(%rbx), %rcx
leaq 0x300e(%rip), %rsi      # 0xb0ef
movsd 0x8(%rsp), %xmm0
movsd 0x18(%rsp), %xmm3
movb $0x4, %al
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
jmp 0x21b0
movq 0x7ef2(%rip), %rax      # 0xfff8
movq (%rax), %rdi
leaq 0x2fc2(%rip), %rsi      # 0xb0d2
xorl %eax, %eax
callq 0x21b0
movsd 0x10(%rsp), %xmm0
movsd 0x8(%rsp), %xmm1
jmp 0x7ea9