setup observations using the sfr ASCII output file.  Setups
    the ability to aggregate flows for groups of segments.  Applies
    only flow to aquier and flow out.

    Parameters
    ----------
    sft_out_file : str
        the existing SFR output file
    seg_group_dict : dict
        a dictionary of SFR segements to aggregate together for a single obs.
        the key value in the dict is the base observation name. If None, all segments
        are used as individual observations. Default is None
    model : flopy.mbase
        a flopy model.  If passed, the observation names will have the datetime of the
        observation appended to them.  If None, the observation names will have the
        stress period appended to them. Default is None.
    include_path : bool
        flag to prepend sfr_out_file path to sfr_obs.config.  Useful for setting up
        process in separate directory for where python is running.


    Returns
    -------
    df : pd.DataFrame
        dataframe of obsnme, obsval and obgnme if inschek run was successful.  Else None

    Note
    ----
    This function writes "sfr_obs.config" which must be kept in the dir where
    "apply_sfr_obs()" is being called during the forward run

def setup_sfr_obs(sfr_out_file,seg_group_dict=None,ins_file=None,model=None,
                  include_path=False):
    """setup observations using the sfr ASCII output file.  Setups
    the ability to aggregate flows for groups of segments.  Applies
    only flow to aquier and flow out.

    Parameters
    ----------
    sft_out_file : str
        the existing SFR output file
    seg_group_dict : dict
        a dictionary of SFR segements to aggregate together for a single obs.
        the key value in the dict is the base observation name. If None, all segments
        are used as individual observations. Default is None
    model : flopy.mbase
        a flopy model.  If passed, the observation names will have the datetime of the
        observation appended to them.  If None, the observation names will have the
        stress period appended to them. Default is None.
    include_path : bool
        flag to prepend sfr_out_file path to sfr_obs.config.  Useful for setting up
        process in separate directory for where python is running.


    Returns
    -------
    df : pd.DataFrame
        dataframe of obsnme, obsval and obgnme if inschek run was successful.  Else None

    Note
    ----
    This function writes "sfr_obs.config" which must be kept in the dir where
    "apply_sfr_obs()" is being called during the forward run

    """

    sfr_dict = load_sfr_out(sfr_out_file)
    kpers = list(sfr_dict.keys())
    kpers.sort()

    if seg_group_dict is None:
        seg_group_dict = {"seg{0:04d}".format(s):s for s in sfr_dict[kpers[0]].segment}
    else:
        warnings.warn("Flow out (flout) of grouped segments will be aggregated... ", PyemuWarning)
    sfr_segs = set(sfr_dict[list(sfr_dict.keys())[0]].segment)
    keys = ["sfr_out_file"]
    if include_path:
        values = [os.path.split(sfr_out_file)[-1]]
    else:
        values = [sfr_out_file]
    for oname,segs in seg_group_dict.items():
        if np.isscalar(segs):
            segs_set = {segs}
            segs = [segs]
        else:
            segs_set = set(segs)
        diff = segs_set.difference(sfr_segs)
        if len(diff) > 0:
            raise Exception("the following segs listed with oname {0} where not found: {1}".
                            format(oname,','.join([str(s) for s in diff])))
        for seg in segs:
            keys.append(oname)
            values.append(seg)

    df_key = pd.DataFrame({"obs_base":keys,"segment":values})
    if include_path:
        pth = os.path.join(*[p for p in os.path.split(sfr_out_file)[:-1]])
        config_file = os.path.join(pth,"sfr_obs.config")
    else:
        config_file = "sfr_obs.config"
    print("writing 'sfr_obs.config' to {0}".format(config_file))
    df_key.to_csv(config_file)

    bd = '.'
    if include_path:
        bd = os.getcwd()
        os.chdir(pth)
    try:
        df = apply_sfr_obs()
    except Exception as e:
        os.chdir(bd)
        raise Exception("error in apply_sfr_obs(): {0}".format(str(e)))
    os.chdir(bd)
    if model is not None:
        dts = (pd.to_datetime(model.start_datetime) + pd.to_timedelta(np.cumsum(model.dis.perlen.array),unit='d')).date
        df.loc[:,"datetime"] = df.kper.apply(lambda x: dts[x])
        df.loc[:,"time_str"] = df.datetime.apply(lambda x: x.strftime("%Y%m%d"))
    else:
        df.loc[:,"time_str"] = df.kper.apply(lambda x: "{0:04d}".format(x))
    df.loc[:,"flaqx_obsnme"] = df.apply(lambda x: "{0}_{1}_{2}".format("fa",x.obs_base,x.time_str),axis=1)
    df.loc[:,"flout_obsnme"] = df.apply(lambda x: "{0}_{1}_{2}".format("fo",x.obs_base,x.time_str),axis=1)

    if ins_file is None:
        ins_file = sfr_out_file + ".processed.ins"

    with open(ins_file,'w') as f:
        f.write("pif ~\nl1\n")
        for fla,flo in zip(df.flaqx_obsnme,df.flout_obsnme):
            f.write("l1 w w !{0}! !{1}!\n".format(fla,flo))

    df = None
    pth = os.path.split(ins_file)[:-1]
    pth = os.path.join(*pth)
    if pth == '':
        pth = '.'
    bd = os.getcwd()
    os.chdir(pth)
    try:
        #df = _try_run_inschek(os.path.split(ins_file)[-1],os.path.split(sfr_out_file+".processed")[-1])
        df = try_process_ins_file(os.path.split(ins_file)[-1],os.path.split(sfr_out_file+".processed")[-1])
    except Exception as e:
        pass
    os.chdir(bd)
    if df is not None:
        df.loc[:,"obsnme"] = df.index.values
        df.loc[:,"obgnme"] = df.obsnme.apply(lambda x: "flaqx" if x.startswith("fa") else "flout")
        return df