def run_model(exe_name, namefile, model_ws='./', silent=False, pause=False, report=False, normal_msg='normal termination', use_async=False, cargs=None):
    "\n    This function will run the model using subprocess.Popen.  It\n    communicates with the model's stdout asynchronously and reports\n    progress to the screen with timestamps\n\n    Parameters\n    ----------\n    exe_name : str\n        Executable name (with path, if necessary) to run.\n    namefile : str\n        Namefile of model to run. The namefile must be the\n        filename of the namefile without the path. Namefile can be None\n        to allow programs that do not require a control file (name file)\n        to be passed as a command line argument.\n    model_ws : str\n        Path to the location of the namefile. (default is the\n        current working directory - './')\n    silent : boolean\n        Echo run information to screen (default is True).\n    pause : boolean, optional\n        Pause upon completion (default is False).\n    report : boolean, optional\n        Save stdout lines to a list (buff) which is returned\n        by the method . (default is False).\n    normal_msg : str or list\n        Normal termination message used to determine if the\n        run terminated normally. More than one message can be provided using\n        a list. (Default is 'normal termination')\n    use_async : boolean\n        asynchronously read model stdout and report with timestamps.  good for\n        models that take long time to run.  not good for models that run\n        really fast\n    cargs : str or list of strings\n        additional command line arguments to pass to the executable.\n        Default is None\n    Returns\n    -------\n    (success, buff)\n    success : boolean\n    buff : list of lines of stdout\n\n    "
    success = False
    buff = []
    if isinstance(normal_msg, str):
        normal_msg = [normal_msg]
    for (idx, s) in enumerate(normal_msg):
        normal_msg[idx] = s.lower()
    exe = which(exe_name)
    if (exe is None):
        import platform
        if (platform.system() in 'Windows'):
            if (not exe_name.lower().endswith('.exe')):
                exe = which((exe_name + '.exe'))
        elif exe_name.lower().endswith('.exe'):
            exe = which(exe_name[:(- 4)])
    if (exe is None):
        raise Exception(f'The program {exe_name} does not exist or is not executable.')
    elif (not silent):
        print(f'FloPy is using the following executable to run the model: {exe}')
    if (namefile is not None):
        if (not os.path.isfile(os.path.join(model_ws, namefile))):
            raise Exception(f'The namefile for this model does not exists: {namefile}')

    def q_output(output, q):
        for line in iter(output.readline, b''):
            q.put(line)
    argv = [exe_name]
    if (namefile is not None):
        argv.append(namefile)
    if (cargs is not None):
        if isinstance(cargs, str):
            cargs = [cargs]
        for t in cargs:
            argv.append(t)
    proc = Popen(argv, stdout=PIPE, stderr=STDOUT, cwd=model_ws)
    if (not use_async):
        while True:
            line = proc.stdout.readline().decode('utf-8')
            if ((line == '') and (proc.poll() is not None)):
                break
            if line:
                for msg in normal_msg:
                    if (msg in line.lower()):
                        success = True
                        break
                line = line.rstrip('\r\n')
                if (not silent):
                    print(line)
                if report:
                    buff.append(line)
            else:
                break
        return (success, buff)
    q = Queue.Queue()
    thread = threading.Thread(target=q_output, args=(proc.stdout, q))
    thread.daemon = True
    thread.start()
    failed_words = ['fail', 'error']
    last = datetime.now()
    lastsec = 0.0
    while True:
        try:
            line = q.get_nowait()
        except Queue.Empty:
            pass
        else:
            if (line == ''):
                break
            line = line.decode().lower().strip()
            if (line != ''):
                now = datetime.now()
                dt = (now - last)
                tsecs = (dt.total_seconds() - lastsec)
                line = f'(elapsed:{tsecs})-->{line}'
                lastsec = (tsecs + lastsec)
                buff.append(line)
                if (not silent):
                    print(line)
                for fword in failed_words:
                    if (fword in line):
                        success = False
                        break
        if (proc.poll() is not None):
            break
    proc.wait()
    thread.join(timeout=1)
    buff.extend(proc.stdout.readlines())
    proc.stdout.close()
    for line in buff:
        for msg in normal_msg:
            if (msg in line.lower()):
                print('success')
                success = True
                break
    if pause:
        input('Press Enter to continue...')
    return (success, buff)
This function will run the model using subprocess.Popen.  It
communicates with the model's stdout asynchronously and reports
progress to the screen with timestamps

Parameters
----------
exe_name : str
    Executable name (with path, if necessary) to run.
namefile : str
    Namefile of model to run. The namefile must be the
    filename of the namefile without the path. Namefile can be None
    to allow programs that do not require a control file (name file)
    to be passed as a command line argument.
model_ws : str
    Path to the location of the namefile. (default is the
    current working directory - './')
silent : boolean
    Echo run information to screen (default is True).
pause : boolean, optional
    Pause upon completion (default is False).
report : boolean, optional
    Save stdout lines to a list (buff) which is returned
    by the method . (default is False).
normal_msg : str or list
    Normal termination message used to determine if the
    run terminated normally. More than one message can be provided using
    a list. (Default is 'normal termination')
use_async : boolean
    asynchronously read model stdout and report with timestamps.  good for
    models that take long time to run.  not good for models that run
    really fast
cargs : str or list of strings
    additional command line arguments to pass to the executable.
    Default is None
Returns
-------
(success, buff)
success : boolean
buff : list of lines of stdout
def run_model(exe_name, namefile, model_ws='./', silent=False, pause=False, report=False, normal_msg='normal termination', use_async=False, cargs=None):
    "\n    This function will run the model using subprocess.Popen.  It\n    communicates with the model's stdout asynchronously and reports\n    progress to the screen with timestamps\n\n    Parameters\n    ----------\n    exe_name : str\n        Executable name (with path, if necessary) to run.\n    namefile : str\n        Namefile of model to run. The namefile must be the\n        filename of the namefile without the path. Namefile can be None\n        to allow programs that do not require a control file (name file)\n        to be passed as a command line argument.\n    model_ws : str\n        Path to the location of the namefile. (default is the\n        current working directory - './')\n    silent : boolean\n        Echo run information to screen (default is True).\n    pause : boolean, optional\n        Pause upon completion (default is False).\n    report : boolean, optional\n        Save stdout lines to a list (buff) which is returned\n        by the method . (default is False).\n    normal_msg : str or list\n        Normal termination message used to determine if the\n        run terminated normally. More than one message can be provided using\n        a list. (Default is 'normal termination')\n    use_async : boolean\n        asynchronously read model stdout and report with timestamps.  good for\n        models that take long time to run.  not good for models that run\n        really fast\n    cargs : str or list of strings\n        additional command line arguments to pass to the executable.\n        Default is None\n    Returns\n    -------\n    (success, buff)\n    success : boolean\n    buff : list of lines of stdout\n\n    "
    success = False
    buff = []
    if isinstance(normal_msg, str):
        normal_msg = [normal_msg]
    for (idx, s) in enumerate(normal_msg):
        normal_msg[idx] = s.lower()
    exe = which(exe_name)
    if (exe is None):
        import platform
        if (platform.system() in 'Windows'):
            if (not exe_name.lower().endswith('.exe')):
                exe = which((exe_name + '.exe'))
        elif exe_name.lower().endswith('.exe'):
            exe = which(exe_name[:(- 4)])
    if (exe is None):
        raise Exception(f'The program {exe_name} does not exist or is not executable.')
    elif (not silent):
        print(f'FloPy is using the following executable to run the model: {exe}')
    if (namefile is not None):
        if (not os.path.isfile(os.path.join(model_ws, namefile))):
            raise Exception(f'The namefile for this model does not exists: {namefile}')

    def q_output(output, q):
        for line in iter(output.readline, b):
            q.put(line)
    argv = [exe_name]
    if (namefile is not None):
        argv.append(namefile)
    if (cargs is not None):
        if isinstance(cargs, str):
            cargs = [cargs]
        for t in cargs:
            argv.append(t)
    proc = Popen(argv, stdout=PIPE, stderr=STDOUT, cwd=model_ws)
    if (not use_async):
        while True:
            line = proc.stdout.readline().decode('utf-8')
            if ((line == ) and (proc.poll() is not None)):
                break
            if line:
                for msg in normal_msg:
                    if (msg in line.lower()):
                        success = True
                        break
                line = line.rstrip('\r\n')
                if (not silent):
                    print(line)
                if report:
                    buff.append(line)
            else:
                break
        return (success, buff)
    q = Queue.Queue()
    thread = threading.Thread(target=q_output, args=(proc.stdout, q))
    thread.daemon = True
    thread.start()
    failed_words = ['fail', 'error']
    last = datetime.now()
    lastsec = 0.0
    while True:
        try:
            line = q.get_nowait()
        except Queue.Empty:
            pass
        else:
            if (line == ):
                break
            line = line.decode().lower().strip()
            if (line != ):
                now = datetime.now()
                dt = (now - last)
                tsecs = (dt.total_seconds() - lastsec)
                line = f'(elapsed:{tsecs})-->{line}'
                lastsec = (tsecs + lastsec)
                buff.append(line)
                if (not silent):
                    print(line)
                for fword in failed_words:
                    if (fword in line):
                        success = False
                        break
        if (proc.poll() is not None):
            break
    proc.wait()
    thread.join(timeout=1)
    buff.extend(proc.stdout.readlines())
    proc.stdout.close()
    for line in buff:
        for msg in normal_msg:
            if (msg in line.lower()):
                print('success')
                success = True
                break
    if pause:
        input('Press Enter to continue...')
    return (success, buff)