Beispiel #1
0
def geocode(scene,
            dem,
            tempdir,
            outdir,
            targetres,
            scaling='linear',
            func_geoback=1,
            func_interp=2,
            nodata=(0, -99),
            sarSimCC=False,
            osvdir=None,
            allow_RES_OSV=False,
            cleanup=True,
            normalization_method=2,
            export_extra=None):
    """
    general function for geocoding SAR images with GAMMA
    
    Parameters
    ----------
    scene: str or ~pyroSAR.drivers.ID
        the SAR scene to be processed
    dem: str
        the reference DEM in GAMMA format
    tempdir: str
        a temporary directory for writing intermediate files
    outdir: str
        the directory for the final GeoTiff output files
    targetres: int
        the target resolution in meters
    scaling: {'linear', 'db'} or list
        the value scaling of the backscatter values; either 'linear', 'db' or a list of both, i.e. ['linear', 'db']
    func_geoback: {0, 1, 2, 3, 4, 5, 6, 7}
        backward geocoding interpolation mode (see GAMMA command geocode_back)
         - 0: nearest-neighbor
         - 1: bicubic spline (default)
         - 2: bicubic-spline, interpolate log(data)
         - 3: bicubic-spline, interpolate sqrt(data)
         - 4: B-spline interpolation (default B-spline degree: 5)
         - 5: B-spline interpolation sqrt(x) (default B-spline degree: 5)
         - 6: Lanczos interpolation (default Lanczos function order: 5)
         - 7: Lanczos interpolation sqrt(x) (default Lanczos function order: 5)

        NOTE: log and sqrt interpolation modes should only be used with non-negative data!
        
        NOTE: Gamma reccomendation for MLI data: "The interpolation should be performed on
        the square root of the data. A mid-order (3 to 5) B-spline interpolation is recommended."
    func_interp: {0, 1, 2, 3}
        output lookup table values in regions of layover, shadow, or DEM gaps (see GAMMA command gc_map)
         - 0: set to (0., 0.)
         - 1: linear interpolation across these regions
         - 2: actual value
         - 3: nn-thinned
    nodata: tuple
        the nodata values for the output files; defined as a tuple with two values, the first for linear,
        the second for logarithmic scaling
    sarSimCC: bool
        perform geocoding with SAR simulation cross correlation?
        If False, geocoding is performed with the Range-Doppler approach using orbit state vectors
    osvdir: str
        a directory for Orbit State Vector files;
        this is currently only used by for Sentinel-1 where two subdirectories POEORB and RESORB are created;
        if set to None, a subdirectory OSV is created in the directory of the unpacked scene.
    allow_RES_OSV: bool
        also allow the less accurate RES orbit files to be used?
        Otherwise the function will raise an error if no POE file exists
    cleanup: bool
        should all files written to the temporary directory during function execution be deleted after processing?
    normalization_method: {1, 2}
        the topographic normalization approach to be used
         - 1: first geocoding, then terrain flattening
         - 2: first terrain flattening, then geocoding; see `Small 2011 <https://doi.org/10.1109/Tgrs.2011.2120616>`_
    export_extra: list or None
        a list of image file IDs to be exported to outdir
         - format is GeoTiff if the file is geocoded and ENVI otherwise. Non-geocoded images can be converted via Gamma
           command data2tiff yet the output was found impossible to read with GIS software
         - scaling of SAR image products is applied as defined by parameter `scaling`
         - see Notes for ID options
    
    Returns
    -------
    
    Note
    ----
    | intermediate output files
    | DEM products are named <scene identifier>_<ID>, e.g. `S1A__IW___A_20141012T162337_inc_geo`
    | SAR products will additionally contain the polarization, e.g. `S1A__IW___A_20141012T162337_VV_grd_mli`
    | IDs in brackets are only written if selected by `export_extra`
    
    - images in range-Doppler geometry
     
      * **grd**: the ground range detected SAR intensity image
      * **grd_mli**: the multi-looked grd image with approached target resolution
      * specific to normalization method 2:
      
        + **pix_ellip_sigma0**: ellipsoid-based pixel area
        + **pix_area_sigma0**: actual illuminated area as obtained from integrating DEM-facets (command pixel_area)
        + **pix_fine**: refined pixel area normalization factor (pix_ellip_sigma0 / pix_area_sigma0)
        + **grd_mli_pan**: the pixel area normalized MLI (grd_mli * pix_fine)
     
    - images in map geometry
     
      * **dem_seg_geo**: dem subsetted to the extent of the intersect between input DEM and SAR image
      * (**u_geo**): zenith angle of surface normal vector n (angle between z and n)
      * (**v_geo**): orientation angle of n (between x and projection of n in xy plane)
      * **inc_geo**: local incidence angle (between surface normal and look vector)
      * (**psi_geo**): projection angle (between surface normal and image plane normal)
      * **pix_geo**: pixel area normalization factor (command gc_map)
      * **ls_map_geo**: layover and shadow map (in map projection)
      * (**sim_sar_geo**): simulated SAR backscatter image
     
    - additional files
     
      * **lut_init**: initial geocoding lookup table
     
    - files specific to SAR simulation cross-correlation geocoding
     
      * **lut_fine**: refined geocoding lookup table
      * **diffpar**: ISP offset/interferogram parameter file
      * **offs**: offset estimates (fcomplex)
      * **coffs**: culled range and azimuth offset estimates (fcomplex)
      * **coffsets**: culled offset estimates and cross correlation values (text format)
      * **ccp**: cross-correlation of each patch (0.0->1.0) (float)
    
    Examples
    --------
    geocode a Sentinel-1 scene and export the local incidence angle map with it
    
    >>> from pyroSAR.gamma import geocode
    >>> filename = 'S1A_IW_GRDH_1SDV_20180829T170656_20180829T170721_023464_028DE0_F7BD.zip'
    >>> geocode(scene=filename, dem='demfile', outdir='outdir', targetres=20, scaling='db',
    >>>         export_extra=['dem_seg_geo', 'inc_geo', 'ls_map_geo'])
    
    .. figure:: figures/gamma_geocode.png
        :scale: 25%
        :align: center
        
        Workflow diagram for function geocode using normalization method 2 for processing a Sentinel-1 Ground Range
        Detected (GRD) scene to radiometrically terrain corrected (RTC) backscatter.
    """
    if normalization_method == 2 and func_interp != 2:
        raise RuntimeError(
            'parameter func_interp must be set to 2 if normalization_method is set to 2; '
            'see documentation of Gamma command pixel_area')

    if isinstance(scene, ID):
        scene = identify(scene.scene)
    elif isinstance(scene, str):
        scene = identify(scene)
    else:
        raise RuntimeError("'scene' must be of type str or pyroSAR.ID")

    if scene.sensor not in ['S1A', 'S1B']:
        raise IOError(
            'this method is currently only available for Sentinel-1. Please stay tuned...'
        )

    if sarSimCC:
        raise IOError(
            'geocoding with cross correlation offset refinement is still in the making. Please stay tuned...'
        )

    if export_extra is not None and not isinstance(export_extra, list):
        raise TypeError(
            "parameter 'export_extra' must either be None or a list")

    for dir in [tempdir, outdir]:
        if not os.path.isdir(dir):
            os.makedirs(dir)

    if scene.is_processed(outdir):
        print('scene {} already processed'.format(scene.outname_base()))
        return

    scaling = [scaling] if isinstance(
        scaling, str) else scaling if isinstance(scaling, list) else []
    scaling = union(scaling, ['db', 'linear'])
    if len(scaling) == 0:
        raise IOError('wrong input type for parameter scaling')

    if scene.compression is not None:
        print('unpacking scene..')
        try:
            scene.unpack(tempdir)
        except RuntimeError:
            print('scene was attempted to be processed before, exiting')
            return
    else:
        scene.scene = os.path.join(tempdir, os.path.basename(scene.file))
        os.makedirs(scene.scene)

    shellscript = os.path.join(scene.scene,
                               scene.outname_base() + '_commands.sh')

    path_log = os.path.join(scene.scene, 'logfiles')
    if not os.path.isdir(path_log):
        os.makedirs(path_log)

    if scene.sensor in ['S1A', 'S1B']:
        print('removing border noise..')
        scene.removeGRDBorderNoise()

    print('converting scene to GAMMA format..')
    convert2gamma(scene,
                  scene.scene,
                  logpath=path_log,
                  outdir=scene.scene,
                  shellscript=shellscript)

    if scene.sensor in ['S1A', 'S1B']:
        print('updating orbit state vectors..')
        if allow_RES_OSV:
            osvtype = ['POE', 'RES']
        else:
            osvtype = 'POE'
        try:
            correctOSV(id=scene,
                       osvdir=osvdir,
                       osvType=osvtype,
                       logpath=path_log,
                       outdir=scene.scene,
                       shellscript=shellscript)
        except RuntimeError:
            print('orbit state vector correction failed for scene {}'.format(
                scene.scene))
            return

    calibrate(scene,
              scene.scene,
              logpath=path_log,
              outdir=scene.scene,
              shellscript=shellscript)

    images = [
        x for x in scene.getGammaImages(scene.scene)
        if x.endswith('_grd') or x.endswith('_slc_cal')
    ]

    products = list(images)

    print('multilooking..')
    for image in images:
        multilook(infile=image,
                  outfile=image + '_mli',
                  targetres=targetres,
                  logpath=path_log,
                  outdir=scene.scene,
                  shellscript=shellscript)

    images = [x + '_mli' for x in images]
    products.extend(images)

    master = images[0]

    # create output names for files to be written
    # appreciated files will be written
    # depreciated files will be set to '-' in the GAMMA function call and are thus not written
    n = Namespace(scene.scene, scene.outname_base())
    n.appreciate(
        ['dem_seg_geo', 'lut_init', 'pix_geo', 'inc_geo', 'ls_map_geo'])
    n.depreciate(['sim_sar_geo', 'u_geo', 'v_geo', 'psi_geo'])

    # if sarSimCC:
    #     n.appreciate(['ccp', 'lut_fine'])

    if export_extra is not None:
        n.appreciate(export_extra)

    ovs_lat, ovs_lon = ovs(dem + '.par', targetres)

    master_par = ISPPar(master + '.par')

    gc_map_args = {
        'DEM_par': dem + '.par',
        'DEM': dem,
        'DEM_seg_par': n.dem_seg_geo + '.par',
        'DEM_seg': n.dem_seg_geo,
        'lookup_table': n.lut_init,
        'lat_ovr': ovs_lat,
        'lon_ovr': ovs_lon,
        'sim_sar': n.sim_sar_geo,
        'u': n.u_geo,
        'v': n.v_geo,
        'inc': n.inc_geo,
        'psi': n.psi_geo,
        'pix': n.pix_geo,
        'ls_map': n.ls_map_geo,
        'frame': 8,
        'ls_mode': func_interp,
        'logpath': path_log,
        'shellscript': shellscript,
        'outdir': scene.scene
    }

    print('creating DEM products..')
    if master_par.image_geometry == 'GROUND_RANGE':
        gc_map_args.update({'GRD_par': master + '.par'})
        diff.gc_map_grd(**gc_map_args)
    else:
        gc_map_args.update({'MLI_par': master + '.par', 'OFF_par': '-'})
        diff.gc_map(**gc_map_args)

    for item in [
            'dem_seg_geo', 'sim_sar_geo', 'u_geo', 'v_geo', 'psi_geo',
            'pix_geo', 'inc_geo', 'ls_map_geo'
    ]:
        if n.isappreciated(item):
            mods = {'data_type': 1} if item == 'ls_map_geo' else None
            par2hdr(n.dem_seg_geo + '.par', n.get(item) + '.hdr', mods)

    sim_width = ISPPar(n.dem_seg_geo + '.par').width

    if sarSimCC:
        raise IOError(
            'geocoding with cross correlation offset refinement is still in the making. Please stay tuned...'
        )
    else:
        lut_final = n.lut_init

    ######################################################################
    # normalization and backward geocoding approach 1 ####################
    ######################################################################
    print('geocoding and normalization..')
    if normalization_method == 1:
        method_suffix = 'geo_norm'
        for image in images:
            diff.geocode_back(data_in=image,
                              width_in=master_par.range_samples,
                              lookup_table=lut_final,
                              data_out=image + '_geo',
                              width_out=sim_width,
                              interp_mode=func_geoback,
                              logpath=path_log,
                              outdir=scene.scene,
                              shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par', image + '_geo.hdr')
            lat.product(data_1=image + '_geo',
                        data_2=n.pix_geo,
                        product=image + '_geo_pan',
                        width=sim_width,
                        bx=1,
                        by=1,
                        logpath=path_log,
                        outdir=scene.scene,
                        shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par', image + '_geo_pan.hdr')
            lat.sigma2gamma(pwr1=image + '_geo_pan',
                            inc=n.inc_geo,
                            gamma=image + '_{}'.format(method_suffix),
                            width=sim_width,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par',
                    image + '_{}.hdr'.format(method_suffix))
            products.extend([image + '_geo', image + '_geo_pan'])
    ######################################################################
    # normalization and backward geocoding approach 2 ####################
    ######################################################################
    elif normalization_method == 2:
        method_suffix = 'norm_geo'
        # newer versions of Gamma enable creating the ratio of ellipsoid based
        # pixel area and DEM-facet pixel area directly with command pixel_area
        if hasarg(diff.pixel_area, 'sigma0_ratio'):
            n.appreciate(['pix_fine'])
            n.depreciate(['pix_area_sigma0'])
            diff.pixel_area(MLI_par=master + '.par',
                            DEM_par=n.dem_seg_geo + '.par',
                            DEM=n.dem_seg_geo,
                            lookup_table=lut_final,
                            ls_map=n.ls_map_geo,
                            inc_map=n.inc_geo,
                            pix_sigma0=n.pix_area_sigma0,
                            sigma0_ratio=n.pix_fine,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(master + '.par', n.pix_fine + '.hdr')
        else:
            n.appreciate(['pix_area_sigma0', 'pix_ellip_sigma0', 'pix_fine'])
            # actual illuminated area as obtained from integrating DEM-facets (pix_area_sigma0 | pix_area_gamma0)
            diff.pixel_area(MLI_par=master + '.par',
                            DEM_par=n.dem_seg_geo + '.par',
                            DEM=n.dem_seg_geo,
                            lookup_table=lut_final,
                            ls_map=n.ls_map_geo,
                            inc_map=n.inc_geo,
                            pix_sigma0=n.pix_area_sigma0,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(master + '.par', n.pix_area_sigma0 + '.hdr')
            # ellipsoid-based pixel area (ellip_pix_sigma0)
            isp.radcal_MLI(
                MLI=master,
                MLI_par=master + '.par',
                OFF_par='-',
                CMLI=master + '_cal',
                refarea_flag=
                1,  # calculate sigma0, scale area by sin(inc_ang)/sin(ref_inc_ang)
                pix_area=n.pix_ellip_sigma0,
                logpath=path_log,
                outdir=scene.scene,
                shellscript=shellscript)
            par2hdr(master + '.par', n.pix_ellip_sigma0 + '.hdr')
            par2hdr(master + '.par', master + '_cal.hdr')
            # ratio of ellipsoid based pixel area and DEM-facet pixel area
            lat.ratio(d1=n.pix_ellip_sigma0,
                      d2=n.pix_area_sigma0,
                      ratio=n.pix_fine,
                      width=master_par.range_samples,
                      bx=1,
                      by=1,
                      logpath=path_log,
                      outdir=scene.scene,
                      shellscript=shellscript)
            par2hdr(master + '.par', n.pix_fine + '.hdr')
        for image in images:
            # sigma0 = MLI * ellip_pix_sigma0 / pix_area_sigma0
            # gamma0 = MLI * ellip_pix_sigma0 / pix_area_gamma0
            lat.product(data_1=image,
                        data_2=n.pix_fine,
                        product=image + '_pan',
                        width=master_par.range_samples,
                        bx=1,
                        by=1,
                        logpath=path_log,
                        outdir=scene.scene,
                        shellscript=shellscript)
            par2hdr(master + '.par', image + '_pan.hdr')
            diff.geocode_back(data_in=image + '_pan',
                              width_in=master_par.range_samples,
                              lookup_table=lut_final,
                              data_out=image + '_pan_geo',
                              width_out=sim_width,
                              interp_mode=func_geoback,
                              logpath=path_log,
                              outdir=scene.scene,
                              shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par', image + '_pan_geo.hdr')
            lat.sigma2gamma(pwr1=image + '_pan_geo',
                            inc=n.inc_geo,
                            gamma=image + '_{}'.format(method_suffix),
                            width=sim_width,
                            logpath=path_log,
                            outdir=scene.scene,
                            shellscript=shellscript)
            par2hdr(n.dem_seg_geo + '.par',
                    image + '_{}.hdr'.format(method_suffix))
            products.extend([image + '_pan', image + '_pan_geo'])
    else:
        raise RuntimeError('unknown option for normalization_method')
    ######################################################################
    print('conversion to (dB and) geotiff..')

    def exporter(data_in, outdir, nodata, scale='linear', dtype=2):
        if scale == 'db':
            if re.search('_geo', os.path.basename(data_in)):
                width = sim_width
                refpar = n.dem_seg_geo + '.par'
            else:
                width = master_par.range_samples
                refpar = master + '.par'
            lat.linear_to_dB(data_in=data_in,
                             data_out=data_in + '_db',
                             width=width,
                             inverse_flag=0,
                             null_value=nodata,
                             logpath=path_log,
                             outdir=scene.scene,
                             shellscript=shellscript)
            par2hdr(refpar, data_in + '_db.hdr')
            data_in += '_db'
        if re.search('_geo', os.path.basename(data_in)):
            outfile = os.path.join(outdir, os.path.basename(data_in) + '.tif')
            disp.data2geotiff(DEM_par=n.dem_seg_geo + '.par',
                              data=data_in,
                              type=dtype,
                              GeoTIFF=outfile,
                              nodata=nodata,
                              logpath=path_log,
                              outdir=scene.scene,
                              shellscript=shellscript)

        else:
            outfile = os.path.join(outdir, os.path.basename(data_in))
            shutil.copyfile(data_in, outfile)
            shutil.copyfile(data_in + '.hdr', outfile + '.hdr')

    for image in images:
        for scale in scaling:
            exporter(data_in=image + '_{}'.format(method_suffix),
                     scale=scale,
                     dtype=2,
                     nodata=dict(zip(('linear', 'db'), nodata))[scale],
                     outdir=outdir)

    if scene.sensor in ['S1A', 'S1B']:
        shutil.copyfile(
            os.path.join(scene.scene, 'manifest.safe'),
            os.path.join(outdir,
                         scene.outname_base() + '_manifest.safe'))

    if export_extra is not None:
        print('exporting extra products..')
        for key in export_extra:
            # SAR image products
            product_match = [x for x in products if x.endswith(key)]
            if len(product_match) > 0:
                for product in product_match:
                    for scale in scaling:
                        exporter(data_in=product,
                                 outdir=outdir,
                                 scale=scale,
                                 dtype=2,
                                 nodata=dict(zip(('linear', 'db'),
                                                 nodata))[scale])
            # ancillary (DEM) products
            elif n.isfile(key) and key not in ['lut_init']:
                filename = n[key]
                dtype = 5 if key == 'ls_map_geo' else 2
                nodata = 0
                exporter(filename, outdir, dtype=dtype, nodata=nodata)
            else:
                print('cannot not export file {}'.format(key))

    shutil.copyfile(shellscript,
                    os.path.join(outdir, os.path.basename(shellscript)))

    if cleanup:
        print('cleaning up temporary files..')
        shutil.rmtree(scene.scene)
Beispiel #2
0
def dem_autocreate(geometry, demType, outfile, buffer=0.01, t_srs=4326, tr=None, logpath=None,
                   username=None, password=None, geoid_mode='gamma'):
    """
    | automatically create a DEM in Gamma format for a defined spatial geometry
    | the following steps will be performed:

    - collect all tiles overlapping with the geometry

      * if they don't yet exist locally they will automatically be downloaded
      * the tiles will be downloaded into the SNAP auxdata directory structure,
        e.g. ``$HOME/.snap/auxdata/dem/SRTM 3Sec``

    - create a mosaic GeoTiff of the same spatial extent as the input geometry
      plus a defined buffer using ``gdalwarp``
    - subtract the EGM96-WGS84 Geoid-Ellipsoid difference and convert the result
      to Gamma format using Gamma command ``srtm2dem``
    
      * this correction is not done for TanDEM-X data, which contains ellipsoid
        heights; see `here <https://geoservice.dlr.de/web/dataguide/tdm90>`_
    
    - if the command ``create_dem_par`` accepts a parameter EPSG and the command ``dem_import`` exists,
      an arbitrary CRS can be defined via parameter ``t_srs``. In this case and if parameter ``t_srs`` is not kept at
      its default of 4326, conversion to Gamma format is done with command ``dem_import`` instead of ``srtm2dem``

    Parameters
    ----------
    geometry: spatialist.vector.Vector
        a vector geometry delimiting the output DEM size; CRS must be WGS84 LatLon (EPSG 4326)
    demType: str
        the type of DEM to be used; see :func:`~pyroSAR.auxdata.dem_autoload` for options
    outfile: str
        the name of the final DEM file
    buffer: float
        a buffer in degrees to create around the geometry
    t_srs: int, str or osr.SpatialReference
        A target geographic reference system in WKT, EPSG, PROJ4 or OPENGIS format.
        See function :func:`spatialist.auxil.crsConvert()` for details.
        Default: `4326 <http://spatialreference.org/ref/epsg/4326/>`_.
    tr: tuple or None
        the target resolution as (xres, yres) in units of ``t_srs``; if ``t_srs`` is kept at its default value of 4326,
        ``tr`` does not need to be defined and the original resolution is preserved;
        in all other cases the default of None is rejected
    logpath: str
        a directory to write Gamma logfiles to
    username: str or None
        (optional) the user name for services requiring registration;
        see :func:`~pyroSAR.auxdata.dem_autoload`
    password: str or None
        (optional) the password for the registration account
    geoid_mode: str
        the software to be used for converting geoid to ellipsoid heights; options:
         - 'gamma'
         - 'gdal'

    Returns
    -------

    """
    
    epsg = crsConvert(t_srs, 'epsg') if t_srs != 4326 else t_srs
    
    if epsg != 4326:
        if not hasarg(diff.create_dem_par, 'EPSG'):
            raise RuntimeError('using a different CRS than 4326 is currently not supported for this version of Gamma')
        if 'dem_import' not in dir(diff):
            raise RuntimeError('using a different CRS than 4326 currently requires command dem_import, '
                               'which is not part of this version of Gamma')
        if tr is None:
            raise RuntimeError('tr needs to be defined if t_srs is not 4326')
    
    if os.path.isfile(outfile):
        print('outfile already exists')
        return
    
    tmpdir = outfile + '__tmp'
    os.makedirs(tmpdir)
    
    try:
        if logpath is not None and not os.path.isdir(logpath):
            os.makedirs(logpath)
        
        vrt = os.path.join(tmpdir, 'dem.vrt')
        dem = os.path.join(tmpdir, 'dem.tif')
        
        print('collecting DEM tiles')
        vrt = dem_autoload([geometry], demType, vrt=vrt, username=username,
                           password=password, buffer=buffer)
        
        # The heights of the TanDEM-X DEM products are ellipsoidal heights, all others are EGM96 Geoid heights
        # Gamma works only with Ellipsoid heights and the offset needs to be corrected
        # starting from GDAL 2.2 the conversion can be done directly in GDAL; see docs of gdalwarp
        gflg = 0
        gdal_geoid = False
        message = 'conversion to Gamma format'
        if demType != 'TDX90m':
            message = 'geoid correction and conversion to Gamma format'
            if geoid_mode == 'gdal':
                gdal_geoid = True
            elif geoid_mode == 'gamma':
                gflg = 2
            else:
                raise RuntimeError("'geoid_mode' not supported")
        
        dem_create(vrt, dem, t_srs=epsg, tr=tr, geoid_convert=gdal_geoid)
        
        outfile_tmp = os.path.join(tmpdir, os.path.basename(outfile))
        
        print(message)
        
        if epsg == 4326:
            # old approach for backwards compatibility
            diff.srtm2dem(SRTM_DEM=dem,
                          DEM=outfile_tmp,
                          DEM_par=outfile_tmp + '.par',
                          gflg=gflg,
                          geoid='-',
                          logpath=logpath,
                          outdir=tmpdir)
        else:
            # new approach enabling an arbitrary target CRS
            diff.create_dem_par(DEM_par=outfile_tmp + '.par',
                                inlist=[''] * 9,
                                EPSG=epsg)
            dem_import_pars = {'input_DEM': dem,
                               'DEM': outfile_tmp,
                               'DEM_par': outfile_tmp + '.par'}
            if gflg == 2:
                home = ExamineGamma().home
                egm96 = os.path.join(home, 'DIFF', 'scripts', 'egm96.dem')
                dem_import_pars['geoid'] = egm96
                dem_import_pars['geoid_par'] = egm96 + '_par'
            
            diff.dem_import(**dem_import_pars)
        
        par2hdr(outfile_tmp + '.par', outfile_tmp + '.hdr', nodata=0)
        
        for suffix in ['', '.par', '.hdr']:
            shutil.copyfile(outfile_tmp + suffix, outfile + suffix)
    
    except RuntimeError as e:
        raise e
    finally:
        shutil.rmtree(tmpdir)