コード例 #1
0
def run(configFile, callback=None):
    """
    Run the hazard calculations.

    This will attempt to run the calculation in parallel by tiling the
    domain, but also provides a sane fallback mechanism to execute
    in serial.

    :param str configFile: path to configuration file

    """

    log.info("Loading hazard calculation settings")

    config = ConfigParser()
    config.read(configFile)

    outputPath = config.get('Output', 'Path')
    inputPath = pjoin(outputPath, 'windfield')
    gridLimit = config.geteval('Region', 'gridLimit')
    numsimulations = config.getint('TrackGenerator', 'NumSimulations')
    yrsPerSim = config.getint('TrackGenerator', 'YearsPerSimulation')
    minRecords = config.getint('Hazard', 'MinimumRecords')
    calculate_confidence = config.getboolean('Hazard', 'CalculateCI')
    extreme_value_distribution = config.get('Hazard', 'ExtremeValueDistribution')

    wf_lon, wf_lat = setDomain(inputPath)

    global MPI, comm
    MPI = attemptParallel()
    comm = MPI.COMM_WORLD
    log.info("Running hazard calculations")
    TG = TileGrid(gridLimit, wf_lon, wf_lat)
    tiles = getTiles(TG)

    #def progress(i):
    #    callback(i, len(tiles))

    comm.barrier()
    hc = HazardCalculator(configFile, TG,
                          numsimulations,
                          minRecords,
                          yrsPerSim,
                          calculate_confidence,
                          extreme_value_distribution
                          )




    hc.dumpHazardFromTiles(tiles)
    log.debug("Finished hazard calculations")
    comm.barrier()

    hc.saveHazard()

    log.info("Completed hazard calculation")
コード例 #2
0
ファイル: landfallRates.py プロジェクト: HyeonJeongKim/tcrm
    def run(self):
        """Execute the analysis"""
        global pp
        pp = attemptParallel()

        self.historic()
        pp.barrier()
        self.synthetic()
        pp.barrier()
        self.plot()
コード例 #3
0
ファイル: landfallRates.py プロジェクト: tonyrafter/tcrm
 def run(self):
     """Execute the analysis"""
     global MPI, comm
     MPI = attemptParallel()
     comm = MPI.COMM_WORLD
     self.historic()
     comm.barrier()
     self.synthetic()
     comm.barrier()
     self.plot()
コード例 #4
0
    def run(self):
        """Execute the analysis"""
        global pp
        pp = attemptParallel()

        self.historic()
        pp.barrier()
        self.synthetic()
        pp.barrier()
        self.plot()
コード例 #5
0
ファイル: __init__.py プロジェクト: squireg/tcrm
def run(configFile, callback=None):
    """
    Run the hazard calculations.

    This will attempt to run the calculation in parallel by tiling the
    domain, but also provides a sane fallback mechanism to execute
    in serial.

    :param configFile: str

    """

    log.info("Loading hazard calculation settings")

    config = ConfigParser()
    config.read(configFile)

    outputPath = config.get('Output', 'Path')
    inputPath = pjoin(outputPath, 'windfield')
    gridLimit = config.geteval('Region', 'gridLimit')
    numsimulations = config.getint('TrackGenerator', 'NumSimulations')
    yrsPerSim = config.getint('TrackGenerator', 'YearsPerSimulation')
    minRecords = config.getint('Hazard', 'MinimumRecords')
    calculate_confidence = config.getboolean('Hazard', 'CalculateCI')

    wf_lon, wf_lat = setDomain(inputPath)

    global pp
    pp = attemptParallel()

    log.info("Running hazard calculations")
    TG = TileGrid(gridLimit, wf_lon, wf_lat)
    tiles = getTiles(TG)

    #def progress(i):
    #    callback(i, len(tiles))

    pp.barrier()
    hc = HazardCalculator(configFile, TG,
                          numsimulations,
                          minRecords,
                          yrsPerSim,
                          calculate_confidence)




    hc.dumpHazardFromTiles(tiles)

    pp.barrier()

    hc.saveHazard()

    log.info("Completed hazard calculation")
コード例 #6
0
    def run(self):
        """Run the longitude crossing evaluation"""
        global pp
        pp = attemptParallel()

        self.historic()

        pp.barrier()

        self.synthetic()

        pp.barrier()

        self.plotCrossingRates()
        self.save()
コード例 #7
0
ファイル: longitudeCrossing.py プロジェクト: tonyrafter/tcrm
    def run(self):
        """Run the longitude crossing evaluation"""
        global MPI, comm
        MPI = attemptParallel()
        comm = MPI.COMM_WORLD
        self.historic()

        comm.barrier()

        self.synthetic()

        comm.barrier()

        self.plotCrossingRates()
        self.save()
コード例 #8
0
ファイル: longitudeCrossing.py プロジェクト: ilai/tcrm
    def run(self):
        """Run the longitude crossing evaluation"""
        global pp
        pp = attemptParallel()

        self.historic()

        pp.barrier()

        self.synthetic()

        pp.barrier()

        self.plotCrossingRates()
        self.save()
コード例 #9
0
    def run(self):
        """Run the track density evaluation"""
        global pp
        pp = attemptParallel()

        self.historic()

        pp.barrier()

        self.synthetic()

        pp.barrier()

        self.plotTrackDensity()
        self.plotTrackDensityPercentiles()

        self.save()
コード例 #10
0
    def run(self):
        """Run the track density evaluation"""
        global MPI, comm
        MPI = attemptParallel()
        comm = MPI.COMM_WORLD
        self.historic()

        comm.barrier()

        self.synthetic()

        comm.barrier()

        self.plotGenesisDensity()
        self.plotGenesisDensityPercentiles()

        self.save()
コード例 #11
0
ファイル: trackDensity.py プロジェクト: jmettes/tcrm
    def run(self):
        """Run the track density evaluation"""
        global pp
        pp = attemptParallel()

        self.historic()

        pp.barrier()

        self.synthetic()
        
        pp.barrier()

        self.plotTrackDensity()
        self.plotTrackDensityPercentiles()

        self.save()
コード例 #12
0
ファイル: __init__.py プロジェクト: greatrussian/tcrm
def run(configFile):
    """
    Run database update

    :param str configFile: path to a configuration file.

    """

    log.info('Running database update')

    config = ConfigParser()
    config.read(configFile)
    outputPath = config.get('Output', 'Path')
    location_db = pjoin(outputPath, 'locations.db')
    if not os.path.exists(location_db):
        location_file = config.get('Input', 'LocationFile')
        buildLocationDatabase(location_db, location_file)

    global MPI, comm
    MPI = attemptParallel()
    comm = MPI.COMM_WORLD
    db = HazardDatabase(configFile)

    db.createDatabase()
    db.setLocations()

    comm.barrier()
    db.processEvents()
    comm.barrier()

    db.processHazard()

    comm.barrier()
    db.processTracks()
    comm.barrier()

    #db.close()
    comm.barrier()
    log.info("Created and populated database")
    log.info("Finished running database creation")
コード例 #13
0
    def run(self):
        """Run the pressure distribution evaluation"""
        global pp
        pp = attemptParallel()

        self.historic()

        pp.barrier()

        self.synthetic()

        pp.barrier()

        self.plotPressureMean()
        self.plotPressureMin()

        self.plotPressureMeanDiff()
        self.plotPressureMinDiff()

        self.plotMinPressureDistribution()
        self.plotMinPressureQuantiles()
        self.save()
コード例 #14
0
    def run(self):
        """Run the pressure distribution evaluation"""
        global pp
        pp = attemptParallel()

        self.historic()

        pp.barrier()

        self.synthetic()

        pp.barrier()

        self.plotPressureMean()
        self.plotPressureMin()

        self.plotPressureMeanDiff()
        self.plotPressureMinDiff()

        self.plotMinPressureDistribution()
        self.plotMinPressureQuantiles()
        self.save()
コード例 #15
0
    def run(self):
        """Run the pressure distribution evaluation"""
        global MPI, comm
        MPI = attemptParallel()
        comm = MPI.COMM_WORLD
        self.historic()

        comm.barrier()

        self.synthetic()

        comm.barrier()

        self.plotPressureMean()
        self.plotPressureMin()

        self.plotPressureMeanDiff()
        self.plotPressureMinDiff()

        self.plotMinPressureDistribution()
        self.plotMinPressureQuantiles()
        self.save()
コード例 #16
0
ファイル: __init__.py プロジェクト: GlobalParametrics/TCRM
    $ python TrackGenerator.py cairns.ini

Note the absence of a '-c' flag (c.f. the normal TCRM command line arguments).
"""

import os
import sys

from TrackGenerator import run
from Utilities.parallel import attemptParallel

if __name__ == "__main__":

    global pp
    pp = attemptParallel()
    import atexit
    atexit.register(pp.finalize)
    try:
        configFile = sys.argv[1]
    except IndexError:

        configFile = __file__.rstrip('.py') + '.ini'

        if not os.path.exists(configFile):
            errorMsg = 'No configuration file specified, please' + \
                       ' type: python main.py {config filename}.ini'
            raise IOError(errorMsg)

    if not os.path.exists(configFile):
        errorMsg = "Configuration file '" + configFile + "' not found"
コード例 #17
0
    $ python TrackGenerator.py cairns.ini

Note the absence of a '-c' flag (c.f. the normal TCRM command line arguments).
"""

import os
import sys

from .TrackGenerator import run
from Utilities.parallel import attemptParallel

if __name__ == "__main__":

    global MPI
    MPI = attemptParallel()
    import atexit
    atexit.register(MPI.Finalize)
    try:
        configFile = sys.argv[1]
    except IndexError:

        configFile = __file__.rstrip('.py') + '.ini'

        if not os.path.exists(configFile):
            errorMsg = 'No configuration file specified, please' + \
                       ' type: python main.py {config filename}.ini'
            raise IOError(errorMsg)

    if not os.path.exists(configFile):
        errorMsg = "Configuration file '" + configFile + "' not found"
コード例 #18
0
def startup():
    """
    Parse command line arguments, set up logging and attempt
    to execute the main TCRM functions.

    """

    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--config_file', help='The configuration file')
    parser.add_argument('-v', '--verbose', help='Verbose output',
                        action='store_true')
    parser.add_argument('-d', '--debug', help='Allow pdb traces',
                        action='store_true')
    args = parser.parse_args()

    configFile = args.config_file

    rootdir = pathLocator.getRootDirectory()
    os.chdir(rootdir)

    config = ConfigParser()
    config.read(configFile)

    logfile = config.get('Logging', 'LogFile')
    logdir = dirname(realpath(logfile))

    # If log file directory does not exist, create it
    if not isdir(logdir):
        try:
            os.makedirs(logdir)
        except OSError:
            logfile = pjoin(os.getcwd(), 'tcrm.log')

    logLevel = config.get('Logging', 'LogLevel')
    verbose = config.getboolean('Logging', 'Verbose')
    datestamp = config.getboolean('Logging', 'Datestamp')
    debug = False

    if args.verbose:
        verbose = True

    if args.debug:
        debug = True

    global MPI, comm
    MPI = attemptParallel()
    import atexit
    atexit.register(MPI.Finalize)
    comm = MPI.COMM_WORLD
    if comm.size > 1 and comm.rank > 0:
        logfile += '-' + str(comm.rank)
        verbose = False  # to stop output to console
    else:
        pass
        #codeStatus = status()
        #print __doc__ + codeStatus

    flStartLog(logfile, logLevel, verbose, datestamp)

    # Switch off minor warning messages
    import warnings
    warnings.filterwarnings("ignore", category=DeprecationWarning)
    warnings.filterwarnings("ignore", category=UserWarning, module="pytz")
    warnings.filterwarnings("ignore", category=UserWarning, module="numpy")
    warnings.filterwarnings("ignore", category=UserWarning,
                            module="matplotlib")

    warnings.filterwarnings("ignore", category=RuntimeWarning)
    checkModules()

    if debug:
        main(configFile)
    else:
        try:
            main(configFile)
        except ImportError as e:
            log.critical("Missing module: {0}".format(e))
            tblines = traceback.format_exc().splitlines()
            for line in tblines:
                log.critical(line.lstrip())
        except Exception:  # pylint: disable=W0703
            # Catch any exceptions that occur and log them (nicely):
            tblines = traceback.format_exc().splitlines()
            for line in tblines:
                log.critical(line.lstrip())
コード例 #19
0
def run():
    lat = np.arange(-30, -4, 2, dtype=float)
    pc = np.arange(900, 991, 5, dtype=float)
    pe = np.arange(995, 1016, dtype=float)
    rm = np.arange(10, 91, 5, dtype=float)
    vfm = np.arange(0, 51, 5, dtype=float)
    gwind = np.zeros((len(lat), len(pc), len(pe), len(rm), len(vfm)))
    swind = np.zeros((len(lat), len(pc), len(pe), len(rm), len(vfm)))
    it = np.nditer(gwind, flags=['multi_index'])
    nn = gwind.size
    #print(nn)

    lon = 120.
    thetaFm = 70
    beta = 1.6
    profileType = "powell"
    blmodel = "kepert"
    i = 0

    # Attempt to start the track generator in parallel
    global MPI
    MPI = attemptParallel()
    comm = MPI.COMM_WORLD

    status = MPI.Status()
    worktag = 0
    resulttag = 1
    idx = [it.multi_index for x in it]
    
    if (comm.rank == 0) and (comm.size > 1):
        w = 0
        p = comm.size -1
        for d in range(1, comm.size):
            print(w)
            if w < len(idx):
                comm.send(idx[w], dest=d, tag=worktag)
                w += 1
            else:
                comm.send(None, dest=d, tag=worktag)
                p = w

        terminated = 0

        while terminated < p:
            try:
                result = comm.recv(source=MPI.ANY_SOURCE, tag=MPI.ANY_TAG, status=status)
            except Exception:
                pass

            d = status.source
            if result:
                gV, sV, workidx = result
                gwind[workidx] = gV
                swind[workidx] = sV
                #gwind[idx[w]], swind[idx[w]] = result

            if w < len(idx):
                comm.send(idx[w], dest=d, tag=worktag)
                w += 1
            else:
                comm.send(None, dest=d, tag=worktag)
                terminated += 1

    elif (comm.rank != 0) and (comm.size > 1):
        while True:
            workidx = comm.recv(source=0, tag=worktag, status=status)
            if workidx is None:
                break
            il, ic, ip, ir, iv = workidx
            print(f"Processing {workidx}")
            gradV, surfV = calculateWindField(lon, lat[il], pe[ip], pc[ic],
                                rm[ir], vfm[iv], thetaFm, beta,
                                profileType=profileType,
                                windFieldType=blmodel)
            results = (np.max(np.abs(gradV)), np.max(surfV), workidx)
            comm.send(results, dest=0, tag=resulttag)

    elif (comm.rank == 0) and (comm.size == 1):
        for x in idx:
            il, ic, ip, ir, iv = x
            print(lat[il], pc[ic], pe[ip], rm[ir], vfm[iv])
            gradV, surfV = calculateWindField(lon, lat[il], pe[ip], pc[ic],
                                              rm[ir], vfm[iv], thetaFm, beta,
                                              profileType=profileType,
                                              windFieldType=blmodel)
            gwind[x] = np.max(np.abs(gradV))
            swind[x] = np.max(surfV)

    comm.barrier()

    coords = [
        ("latitude", lat, dict(long_name="Latitude",
                            units="degrees_south")),
        ("pcentre", pc, dict(long_name="Central pressure",
                            units="hPa")),
        ("penv", pe, dict(long_name="Environmental pressure",
                        units="hPa")),
        ("rmax", rm, dict(long_name="Radius to maximum winds",
                        units="km")),
        ("vfm", vfm, dict(long_name="Forward speed",
                        units="km/h"))
    ]

    dims = ["latitude", 'pcentre', 'penv', 'rmax', 'vfm']
    gattrs = {
        "long_name": "Gradient level wind speed",
        "profile": profileType,
        "blmodel": blmodel,
        "description": "maximum gradient level wind speed",
        "units": "m s-1",
        }
    sattrs = {
        "long_name": "Surface wind speed",
        "profile": profileType,
        "blmodel": blmodel,
        "description": "maximum 0.2-s wind gust",
        "units": "m s-1",
        }

    if comm.rank == 0:
        gda = xr.DataArray(gwind, dims=dims, coords=coords, attrs=gattrs)
        sda = xr.DataArray(swind, dims=dims, coords=coords, attrs=sattrs)
        ds = xr.Dataset()
        ds['gradwind'] = gda
        ds['surfwind'] = sda
        ds.to_netcdf("output.nc")

    MPI.Finalize()
コード例 #20
0
ファイル: tcrm.py プロジェクト: squireg/tcrm
def startup():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--config_file', help='The configuration file')
    parser.add_argument('-v', '--verbose', help='Verbose output',
                        action='store_true')
    parser.add_argument('-d', '--debug', help='Allow pdb traces',
                        action='store_true')
    args = parser.parse_args()

    configFile = args.config_file

    rootdir = pathLocator.getRootDirectory()
    os.chdir(rootdir)

    config = ConfigParser()
    config.read(configFile)

    logfile = config.get('Logging', 'LogFile')
    logdir = dirname(realpath(logfile))

    # If log file directory does not exist, create it
    if not isdir(logdir):
        try:
            os.makedirs(logdir)
        except OSError:
            logfile = pjoin(os.getcwd(), 'tcrm.log')

    logLevel = config.get('Logging', 'LogLevel')
    verbose = config.getboolean('Logging', 'Verbose')
    debug = False

    if args.verbose:
        verbose = True

    #if not verbose:
    #    logLevel = 'ERROR'
    #    verbose = True

    if args.debug:
        debug = True

    global pp
    pp = attemptParallel()
    import atexit
    atexit.register(pp.finalize)

    if pp.size() > 1 and pp.rank() > 0:
        logfile += '-' + str(pp.rank())
        verbose = False  # to stop output to console
    else:
        pass
        #codeStatus = status()
        #print __doc__ + codeStatus

    flStartLog(logfile, logLevel, verbose)

    # Switch off minor warning messages
    import warnings
    warnings.filterwarnings("ignore", category=DeprecationWarning)
    warnings.filterwarnings("ignore", category=UserWarning, module="pytz")
    warnings.filterwarnings("ignore", category=UserWarning, module="numpy")
    warnings.filterwarnings("ignore", category=UserWarning,
                            module="matplotlib")
    
    warnings.filterwarnings("ignore", category=RuntimeWarning)
    
    if debug:
        main(configFile)
    else:
        try:
            main(configFile)
        except Exception:  # pylint: disable=W0703
            # Catch any exceptions that occur and log them (nicely):
            tblines = traceback.format_exc().splitlines()
            for line in tblines:
                log.critical(line.lstrip())
コード例 #21
0
ファイル: __init__.py プロジェクト: jmettes/tcrm
def run(configFile, callback=None):
    """
    Run the wind field calculations.

    :param str configFile: path to a configuration file.
    :param func callback: optional callback function to track progress.

    """

    log.info('Loading wind field calculation settings')

    # Get configuration

    config = ConfigParser()
    config.read(configFile)

    outputPath = config.get('Output', 'Path')
    profileType = config.get('WindfieldInterface', 'profileType')
    windFieldType = config.get('WindfieldInterface', 'windFieldType')
    beta = config.getfloat('WindfieldInterface', 'beta')
    beta1 = config.getfloat('WindfieldInterface', 'beta1')
    beta2 = config.getfloat('WindfieldInterface', 'beta2')
    thetaMax = config.getfloat('WindfieldInterface', 'thetaMax')
    margin = config.getfloat('WindfieldInterface', 'Margin')
    resolution = config.getfloat('WindfieldInterface', 'Resolution')
    domain = config.get('WindfieldInterface', 'Domain')

    windfieldPath = pjoin(outputPath, 'windfield')
    trackPath = pjoin(outputPath, 'tracks')
    windfieldFormat = 'gust-%i-%04d.nc'

    gridLimit = None
    if config.has_option('Region','gridLimit'):
        gridLimit = config.geteval('Region', 'gridLimit')

    if config.has_option('WindfieldInterface', 'gridLimit'):
        gridLimit = config.geteval('WindfieldInterface', 'gridLimit')

    if config.has_section('Timeseries'):
        if config.has_option('Timeseries', 'Extract'):
            if config.getboolean('Timeseries', 'Extract'):
                from Utilities.timeseries import Timeseries
                log.debug("Timeseries data will be extracted")
                ts = Timeseries(configFile)
                timestepCallback = ts.extract

    else:
        def timestepCallback(*args):
            """Dummy timestepCallback function"""
            pass

    thetaMax = math.radians(thetaMax)

    # Attempt to start the track generator in parallel
    global pp
    pp = attemptParallel()

    log.info('Running windfield generator')

    wfg = WindfieldGenerator(config=config,
                             margin=margin,
                             resolution=resolution,
                             profileType=profileType,
                             windFieldType=windFieldType,
                             beta=beta,
                             beta1=beta1,
                             beta2=beta2,
                             thetaMax=thetaMax,
                             gridLimit=gridLimit,
                             domain=domain)

    msg = 'Dumping gusts to %s' % windfieldPath
    log.info(msg)

    # Get the trackfile names and count

    files = os.listdir(trackPath)
    trackfiles = [pjoin(trackPath, f) for f in files if f.startswith('tracks')]
    nfiles = len(trackfiles)

    def progressCallback(i):
        """Define the callback function"""
        callback(i, nfiles)

    msg = 'Processing %d track files in %s' % (nfiles, trackPath)
    log.info(msg)

    # Do the work

    pp.barrier()

    wfg.dumpGustsFromTrackfiles(trackfiles, windfieldPath, windfieldFormat,
                                progressCallback, timestepCallback)
    try:
        ts.shutdown()
    except NameError:
        pass

    pp.barrier()

    log.info('Completed windfield generator')
コード例 #22
0
ファイル: __init__.py プロジェクト: Jack-ee/tcrm
def run(configFile, callback=None):
    """
    Run the wind field calculations.

    :param str configFile: path to a configuration file.
    :param func callback: optional callback function to track progress.

    """

    log.info('Loading wind field calculation settings')

    # Get configuration

    config = ConfigParser()
    config.read(configFile)

    profileType = config.get('WindfieldInterface', 'profileType')
    windFieldType = config.get('WindfieldInterface', 'windFieldType')
    beta = config.getfloat('WindfieldInterface', 'beta')
    beta1 = config.getfloat('WindfieldInterface', 'beta1')
    beta2 = config.getfloat('WindfieldInterface', 'beta2')
    thetaMax = config.getfloat('WindfieldInterface', 'thetaMax')
    margin = config.getfloat('WindfieldInterface', 'Margin')
    resolution = config.getfloat('WindfieldInterface', 'Resolution')
    domain = config.get('WindfieldInterface', 'Domain')

    outputPath = config.get('Output', 'Path')
    windfieldPath = pjoin(outputPath, 'windfield')
    trackPath = pjoin(outputPath, 'tracks')

    gridLimit = None
    if config.has_option('Region', 'gridLimit'):
        gridLimit = config.geteval('Region', 'gridLimit')

    if config.has_option('WindfieldInterface', 'gridLimit'):
        gridLimit = config.geteval('WindfieldInterface', 'gridLimit')

    if config.getboolean('Timeseries', 'Extract', fallback=False):
        from Utilities.timeseries import Timeseries
        ts = Timeseries(configFile)
        timestepCallback = ts.extract
    else:
        timestepCallback = None

    multipliers = None
    if config.has_option('Input', 'Multipliers'):
        multipliers = config.get('Input', 'Multipliers')

    thetaMax = math.radians(thetaMax)

    # Attempt to start the track generator in parallel
    global MPI
    MPI = attemptParallel()
    comm = MPI.COMM_WORLD

    log.info('Running windfield generator')

    wfg = WindfieldGenerator(config=config,
                             margin=margin,
                             resolution=resolution,
                             profileType=profileType,
                             windFieldType=windFieldType,
                             beta=beta,
                             beta1=beta1,
                             beta2=beta2,
                             thetaMax=thetaMax,
                             gridLimit=gridLimit,
                             domain=domain,
                             multipliers=multipliers,
                             windfieldPath=windfieldPath)

    log.info(f'Dumping gusts to {windfieldPath}')

    # Get the trackfile names and count

    files = os.listdir(trackPath)
    trackfiles = [pjoin(trackPath, f) for f in files if f.startswith('tracks')]
    nfiles = len(trackfiles)

    log.info('Processing {0} track files in {1}'.format(nfiles, trackPath))

    # Do the work

    comm.barrier()

    wfg.dumpGustsFromTrackfiles(trackfiles, windfieldPath, timestepCallback)
    try:
        ts.shutdown()
    except NameError:

        pass

    comm.barrier()

    log.info('Completed windfield generator')
コード例 #23
0
def run(configFile, callback=None):
    """
    Run the wind field calculations.

    :param str configFile: path to a configuration file.
    :param func callback: optional callback function to track progress.

    """

    log.info('Loading wind field calculation settings')

    # Get configuration

    config = ConfigParser()
    config.read(configFile)

    profileType = config.get('WindfieldInterface', 'profileType')
    windFieldType = config.get('WindfieldInterface', 'windFieldType')
    beta = config.getfloat('WindfieldInterface', 'beta')
    beta1 = config.getfloat('WindfieldInterface', 'beta1')
    beta2 = config.getfloat('WindfieldInterface', 'beta2')
    thetaMax = config.getfloat('WindfieldInterface', 'thetaMax')
    margin = config.getfloat('WindfieldInterface', 'Margin')
    resolution = config.getfloat('WindfieldInterface', 'Resolution')
    domain = config.get('WindfieldInterface', 'Domain')

    outputPath = config.get('Output', 'Path')
    windfieldPath = pjoin(outputPath, 'windfield')
    trackPath = pjoin(outputPath, 'tracks')

    gridLimit = None
    if config.has_option('Region', 'gridLimit'):
        gridLimit = config.geteval('Region', 'gridLimit')

    if config.has_option('WindfieldInterface', 'gridLimit'):
        gridLimit = config.geteval('WindfieldInterface', 'gridLimit')

    if config.has_section('Timeseries'):
        if config.has_option('Timeseries', 'Extract'):
            if config.getboolean('Timeseries', 'Extract'):
                from Utilities.timeseries import Timeseries
                log.debug("Timeseries data will be extracted")
                ts = Timeseries(configFile)
                timestepCallback = ts.extract
            else:

                def timestepCallback(*args):
                    """Dummy timestepCallback function"""
                    pass

    else:

        def timestepCallback(*args):
            """Dummy timestepCallback function"""
            pass

    thetaMax = math.radians(thetaMax)

    # Attempt to start the track generator in parallel
    global pp
    pp = attemptParallel()

    log.info('Running windfield generator')

    wfg = WindfieldGenerator(config=config,
                             margin=margin,
                             resolution=resolution,
                             profileType=profileType,
                             windFieldType=windFieldType,
                             beta=beta,
                             beta1=beta1,
                             beta2=beta2,
                             thetaMax=thetaMax,
                             gridLimit=gridLimit,
                             domain=domain)

    msg = 'Dumping gusts to %s' % windfieldPath
    log.info(msg)

    # Get the trackfile names and count

    files = os.listdir(trackPath)
    trackfiles = [pjoin(trackPath, f) for f in files if f.startswith('tracks')]
    nfiles = len(trackfiles)

    def progressCallback(i):
        """Define the callback function"""
        callback(i, nfiles)

    msg = 'Processing %d track files in %s' % (nfiles, trackPath)
    log.info(msg)

    # Do the work

    pp.barrier()

    wfg.dumpGustsFromTrackfiles(trackfiles, windfieldPath, timestepCallback)

    try:
        ts.shutdown()
    except NameError:
        pass

    pp.barrier()

    log.info('Completed windfield generator')