/*
 * Helper file for repetitive actions when collapsing a FITS
 * file along one or more dimensions
 *
 * In order to use this, you have
 * #define COLLAPSEACTION
 * and then
 * #include "collapse_helper.cpp"
 *
 * The integer variable axis determines along which axis to collapse:
 * axis = 1    x
 * axis = 2    y
 * axis = 3    z
 * axis = 12  xy
 * axis = 13  xz
 * axis = 23  yz
 *
 * The result will be stored in the *this FITS, which will be of type R8.
 *
 */

long _x, _y, _z, _index, _n, _ne;
double _value, _bscale, _bzero;
char key[81];

_index = 0;
_value = 0.0;
_bscale = source.bscale;
_bzero = source.bzero;

switch (axis) {
    case 1:
        create(source.Naxis(2), source.Naxis(3), R8);
        switch (source.membits) {
            case I1:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        _ne = source.Naxis(1);
                        PRECOLLAPSEACTION;
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i1data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I2:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        _ne = source.Naxis(1);
                        PRECOLLAPSEACTION;
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i2data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I4:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        _ne = source.Naxis(1);
                        PRECOLLAPSEACTION;
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i4data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I8:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        _ne = source.Naxis(1);
                        PRECOLLAPSEACTION;
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i8data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case R4:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        _ne = 0;
                        PRECOLLAPSEACTION;
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            _value = source.r4data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case R8:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        _ne = 0;
                        PRECOLLAPSEACTION;
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            _value = source.r8data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            default:
            break;
        }
        CopyHeader(source);
        updateHeader();
        SetFloatKey("CRPIX1", source.getCRPIX(2));
        SetFloatKey("CRPIX2", source.getCRPIX(3));
        SetFloatKey("CRVAL1", source.getCRVAL(2));
        SetFloatKey("CRVAL2", source.getCRVAL(3));
        SetFloatKey("CDELT1", source.getCDELT(2));
        SetFloatKey("CDELT2", source.getCDELT(3));
        source.GetStringKey("CTYPE2", key);
        SetStringKey("CTYPE1", key);
        source.GetStringKey("CTYPE3", key);
        SetStringKey("CTYPE2", key);
        source.GetStringKey("CUNIT2", key);
        SetStringKey("CUNIT1", key);
        source.GetStringKey("CUNIT3", key);
        SetStringKey("CUNIT2", key);
        DeleteKey("CDELT3");
        DeleteKey("CD3_3");
        DeleteKey("CD1_1");
        DeleteKey("CD1_2");
        DeleteKey("CD2_1");
        DeleteKey("CD2_2");
        DeleteKey("CTYPE3");
        DeleteKey("CUNIT3");
        DeleteKey("CRVAL3");
        DeleteKey("CRPIX3");
        DeleteKey("CROTA1");
        DeleteKey("CROTA2");

        break;
    case 2:
        create(source.Naxis(1), source.Naxis(3), R8);
        switch (source.membits) {
            case I1:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(2);
                        PRECOLLAPSEACTION;
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i1data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I2:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(2);
                        PRECOLLAPSEACTION;
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i2data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I4:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(2);
                        PRECOLLAPSEACTION;
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i4data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I8:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(2);
                        PRECOLLAPSEACTION;
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i8data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case R4:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = 0;
                        PRECOLLAPSEACTION;
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            _value = source.r4data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case R8:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = 0;
                        PRECOLLAPSEACTION;
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            _value = source.r8data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            default:
            break;
        }
        CopyHeader(source);
        updateHeader();
        SetFloatKey("CRPIX2", source.getCRPIX(3));
        SetFloatKey("CRVAL2", source.getCRVAL(3));
        SetFloatKey("CDELT2", source.getCDELT(3));
        source.GetStringKey("CTYPE3", key);
        SetStringKey("CTYPE2", key);
        source.GetStringKey("CUNIT3", key);
        SetStringKey("CUNIT2", key);
        DeleteKey("CDELT3");
        DeleteKey("CD3_3");
        DeleteKey("CD1_1");
        DeleteKey("CD1_2");
        DeleteKey("CD2_1");
        DeleteKey("CD2_2");
        DeleteKey("CTYPE3");
        DeleteKey("CUNIT3");
        DeleteKey("CRVAL3");
        DeleteKey("CRPIX3");
        DeleteKey("CROTA1");
        DeleteKey("CROTA2");

        break;
    case 3:
        create(source.Naxis(1), source.Naxis(2), R8);
        switch (source.membits) {
            case I1:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(3);
                        PRECOLLAPSEACTION;
                        for (_z = 0; _z < source.Naxis(3); _z++) {
                            COLLAPSEACTION(source.i1data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I2:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(3);
                        PRECOLLAPSEACTION;
                        for (_z = 0; _z < source.Naxis(3); _z++) {
                            COLLAPSEACTION(source.i2data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I4:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(3);
                        PRECOLLAPSEACTION;
                        for (_z = 0; _z < source.Naxis(3); _z++) {
                            COLLAPSEACTION(source.i4data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case I8:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = source.Naxis(3);
                        PRECOLLAPSEACTION;
                        for (_z = 0; _z < source.Naxis(3); _z++) {
                            COLLAPSEACTION(source.i8data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case R4:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = 0;
                        PRECOLLAPSEACTION;
                        for (_z = 0; _z < source.Naxis(3); _z++) {
                            _value = source.r4data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            case R8:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    for (_x = 0; _x < source.Naxis(1); _x++) {
                        _ne = 0;
                        PRECOLLAPSEACTION;
                        for (_z = 0; _z < source.Naxis(3); _z++) {
                            _value = source.r8data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                        POSTCOLLAPSEACTION(r8data[_index], _ne);
                        _index++;
                    }
                }
            break;
            default:
            break;
        }
        CopyHeader(source);
        updateHeader();
        DeleteKey("CDELT3");
        DeleteKey("CD3_3");
        DeleteKey("CTYPE3");
        DeleteKey("CUNIT3");
        DeleteKey("CRVAL3");
        DeleteKey("CRPIX3");

        break;
    case 12:
        create(source.Naxis(3), 1, R8);
        _n = source.Naxis(1)*source.Naxis(2);
        switch (source.membits) {
            case I1:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i1data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I2:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i2data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I4:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i4data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I8:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i8data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case R4:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    _ne = 0;
                    PRECOLLAPSEACTION;
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            _value = source.r4data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case R8:
                for (_z = 0; _z < source.Naxis(3); _z++) {
                    _ne = 0;
                    PRECOLLAPSEACTION;
                    for (_y = 0; _y < source.Naxis(2); _y++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            _value = source.r8data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            default:
            break;
        }
        CopyHeader(source);
        updateHeader();
        SetFloatKey("CRPIX1", source.getCRPIX(3));
        SetFloatKey("CRVAL1", source.getCRVAL(3));
        SetFloatKey("CDELT1", source.getCDELT(3));
        source.GetStringKey("CTYPE3", key);
        SetStringKey("CTYPE1", key);
        source.GetStringKey("CUNIT3", key);
        SetStringKey("CUNIT1", key);
        DeleteKey("CDELT3");
        DeleteKey("CDELT2");
        DeleteKey("CD3_3");
        DeleteKey("CD1_1");
        DeleteKey("CD1_2");
        DeleteKey("CD2_1");
        DeleteKey("CD2_2");
        DeleteKey("CTYPE3");
        DeleteKey("CUNIT3");
        DeleteKey("CRVAL3");
        DeleteKey("CRPIX3");
        DeleteKey("CTYPE2");
        DeleteKey("CUNIT2");
        DeleteKey("CRVAL2");
        DeleteKey("CRPIX2");
        DeleteKey("CROTA1");
        DeleteKey("CROTA2");

        break;
    case 23:
        create(source.Naxis(1), 1, R8);
        _n = source.Naxis(2)*source.Naxis(3);
        switch (source.membits) {
            case I1:
                for (_x = 0; _x < source.Naxis(1); _x++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i1data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I2:
                for (_x = 0; _x < source.Naxis(1); _x++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i2data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I4:
                for (_x = 0; _x < source.Naxis(1); _x++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i4data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I8:
                for (_x = 0; _x < source.Naxis(1); _x++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            COLLAPSEACTION(source.i8data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case R4:
                for (_x = 0; _x < source.Naxis(1); _x++) {
                    _ne = 0;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            _value = source.r4data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case R8:
                for (_x = 0; _x < source.Naxis(1); _x++) {
                    _ne = 0;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_y = 0; _y < source.Naxis(2); _y++) {
                            _value = source.r8data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            default:
            break;
        }
        CopyHeader(source);
        updateHeader();
        DeleteKey("CDELT3");
        DeleteKey("CDELT2");
        DeleteKey("CD3_3");
        DeleteKey("CD1_2");
        DeleteKey("CD2_1");
        DeleteKey("CD2_2");
        DeleteKey("CTYPE3");
        DeleteKey("CUNIT3");
        DeleteKey("CRVAL3");
        DeleteKey("CRPIX3");
        DeleteKey("CTYPE2");
        DeleteKey("CUNIT2");
        DeleteKey("CRVAL2");
        DeleteKey("CRPIX2");
        DeleteKey("CROTA2");

        break;
    case 13:
        create(source.Naxis(2), 1, R8);
        _n = source.Naxis(1) * source.Naxis(3);
        switch (source.membits) {
            case I1:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i1data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I2:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i2data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I4:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i4data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case I8:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    _ne = _n;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            COLLAPSEACTION(source.i8data[source.C_I(_x, _y, _z)]*_bscale+_bzero, r8data[_index]);
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case R4:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    _ne = 0;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            _value = source.r4data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            case R8:
                for (_y = 0; _y < source.Naxis(2); _y++) {
                    _ne = 0;
                    PRECOLLAPSEACTION;
                    for (_z = 0; _z < source.Naxis(3); _z++) {
                        for (_x = 0; _x < source.Naxis(1); _x++) {
                            _value = source.r8data[source.C_I(_x, _y, _z)];
                            if (gsl_finite(_value)) {
                                _ne++;
                                COLLAPSEACTION(_value, r8data[_index]);
                            }
                        }
                    }
                    POSTCOLLAPSEACTION(r8data[_index], _ne);
                    _index++;
                }
            break;
            default:
            break;
        }
        CopyHeader(source);
        updateHeader();
        SetFloatKey("CRPIX1", source.getCRPIX(2));
        SetFloatKey("CRVAL1", source.getCRVAL(2));
        SetFloatKey("CDELT1", source.getCDELT(2));
        source.GetStringKey("CTYPE2", key);
        SetStringKey("CTYPE1", key);
        source.GetStringKey("CUNIT2", key);
        SetStringKey("CUNIT1", key);
        DeleteKey("CDELT3");
        DeleteKey("CDELT2");
        DeleteKey("CD3_3");
        DeleteKey("CD1_1");
        DeleteKey("CD1_2");
        DeleteKey("CD2_1");
        DeleteKey("CD2_2");
        DeleteKey("CTYPE3");
        DeleteKey("CUNIT3");
        DeleteKey("CRVAL3");
        DeleteKey("CRPIX3");
        DeleteKey("CTYPE2");
        DeleteKey("CUNIT2");
        DeleteKey("CRVAL2");
        DeleteKey("CRPIX2");
        DeleteKey("CROTA1");
        DeleteKey("CROTA2");

        break;
    default:
    break;
}
