def get_conv_factors(self, spcdb_dir): """ Gets conversion factors used in budget computations Arguments: spcdb_dir : str Path to the species_database.yml file """ # Read the species database path = os.path.join(spcdb_dir, "species_database.yml") spcdb = yaml_load_file(open(path)) # Molecular weights [kg mol-1], as taken from the species database self.mw = {} self.mw["O3"] = spcdb["O3"]["MW_g"] * 1.0e-3 self.mw["Ox"] = self.mw["O3"] self.mw["Air"] = constants.MW_AIR_g * 1.0e-3 # kg/s --> Tg/d self.kg_s_to_tg_a_value = 86400.0 * self.d_per_a * 1e-9
def __init__(self, devstr, devdir, plotsdir, year, overwrite): """ Initializes the _GlobVars class. Args: ----- devstr : str Label denoting the "Dev" version. devdir : str Directory where benchmark diagnostic files are found. plotsdir : str Directory where plots & tables will be created. year : int Year of the benchmark simulation. overwrite : bool Denotes whether to ovewrite existing budget tables. """ """ Initializes the _GlobVars class. """ # ------------------------------ # Arguments from outside # ------------------------------ self.devstr = devstr self.devdir = devdir self.plotsdir = plotsdir self.overwrite = overwrite # ------------------------------ # Benchmark year # ------------------------------ self.y0 = year self.y1 = self.y0 + 1 self.y0_str = "{}".format(self.y0) self.y1_str = "{}".format(self.y1) # ------------------------------ # Species info # ------------------------------ # Directory where diagnostic files are found datadir = join(devstr, "OutputDir") # List of species (and subsets for the trop & strat) self.species_list = ["BCPI", "OCPI", "SO4", "DST1", "SALA", "SALC" ] # Read the species database try: path = join(datadir, "species_database.yml") spcdb = yaml_load_file(open(path)) except FileNotFoundError: path = join(os.path.dirname(__file__), "species_database.yml") spcdb = yaml_load_file(open(path)) # Molecular weights [g mol-1], as taken from the species database self.mw = {} for v in self.species_list: self.mw[v] = spcdb[v]["MW_g"] self.mw["Air"] = constants.MW_AIR * 1.0e3 # Get the list of relevant AOD diagnostics from a YAML file path = join(os.path.dirname(__file__), "aod_species.yml") aod = yaml_load_file(open(path)) self.aod_list = [v for v in aod.keys() if "Dust" in v or "Hyg" in v] # Descriptive names self.spc2name = {"BCPI": "Black Carbon", "DST1": "Dust", "OCPI": "Organic Carbon", "SO4" : "Sulfate", "SALA": "Sea Salt (accum)", "SALC": "Sea Salt (coarse)"} # ------------------------------ # Collection file lists # ------------------------------ Aerosols = join(datadir, "*.Aerosols.{}*.nc4".format(self.y0_str)) StateMet = join(datadir, "*.StateMet.{}*.nc4".format(self.y0_str)) SpeciesConc = join(datadir, "*.SpeciesConc.{}*.nc4".format(self.y0_str)) # ------------------------------ # Read data collections # ------------------------------ # Diagnostics self.ds_aer = xr.open_mfdataset(Aerosols, data_vars=self.aod_list) self.ds_cnc = xr.open_mfdataset(SpeciesConc) self.ds_met = xr.open_mfdataset(StateMet) # Troposphere mask self.tropmask = get_troposphere_mask(self.ds_met) # Number of vertical levels self.N_LEVS = self.ds_cnc.dims["lev"] # Set a flag to denote if this data is from GCHP self.is_gchp = "nf" in self.ds_cnc.dims.keys() # ------------------------------ # Months and days # ------------------------------ self.N_MONTHS = 12 self.N_MONTHS_FLOAT = self.N_MONTHS * 1.0 # Days per month in the benchmark year self.d_per_mon = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.d_per_mon[t] = monthrange(self.y0, t+1)[1] * 1.0 # Days in the benchmark year self.d_per_yr = np.sum(self.d_per_mon) # Fraction of year occupied by each month self.frac_of_yr = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.frac_of_yr[t] = self.d_per_mon[t] / self.d_per_yr # -------------------------------- # Surface area # (kludgey but it works) # -------------------------------- if self.is_gchp: area = self.ds_met["Met_AREAM2"].values a = area.shape self.area_m2 = np.zeros([a[0], N_LEVS, a[1], a[2], a[3]]) for t in range(self.N_MONTHS): for k in range(self.N_LEVS): self.area_m2[t,k,:,:,:] = area[t,:,:,:] self.total_area_m2 = np.sum(self.area_m2[0,0,:,:,:]) else: area = self.ds_met["AREA"].values a = area.shape self.area_m2 = np.zeros([a[0], self.N_LEVS, a[1], a[2]]) for t in range(self.N_MONTHS): for k in range(self.N_LEVS): self.area_m2[t,k,:,:] = area[t,:,:] self.total_area_m2 = np.sum(self.area_m2[0,0,:,:]) # ------------------------------ # Conversion factors # ------------------------------ # v/v dry --> Tg self.vv_to_Tg = {} for spc in self.species_list: self.vv_to_Tg[spc] = self.ds_met["Met_AD"].values \ * (self.mw[spc] / self.mw["Air"]) * 1e-9
def __init__(self, devstr, devdir, devrstdir, year, dst, is_gchp, overwrite, spcdb_dir): """ Initializes the _GlobVars class. Args: ----- devstr : str Label denoting the "Dev" version. devdir : str Directory where diagnostic files are found. devrstdir : str Directory where restart files are found. dst : str Directory where plots & tables will be created. year : int Year of the benchmark simulation. is_gchp : bool Denotes if this is GCHP (True) or GCC (False) data. overwrite : bool Denotes whether to ovewrite existing budget tables. spcdb_dir : str Directory where species_database.yml is stored. """ # ------------------------------ # Arguments from outside # ------------------------------ self.devstr = devstr self.devdir = devdir self.devrstdir = devrstdir self.dst = dst self.is_gchp = is_gchp self.overwrite = overwrite # ------------------------------ # Benchmark year # ------------------------------ self.y0 = year self.y1 = self.y0 + 1 self.y0_str = "{}".format(self.y0) self.y1_str = "{}".format(self.y1) # ------------------------------ # Collection file lists # ------------------------------ # Restarts if self.is_gchp: RstInit = join(self.devrstdir, "initial_GEOSChem_rst.c48_TransportTracers.nc") RstFinal = join( self.devrstdir, "gcchem_internal_checkpoint.restart.{}*.nc4".format( self.y1_str)) else: RstInit = join(self.devrstdir, "GEOSChem.Restart.{}*nc4".format(self.y0_str)) RstFinal = join(self.devrstdir, "GEOSChem.Restart.{}*.nc4".format(self.y1_str)) # Diagnostics HemcoDiag = join(self.devdir, "HEMCO_diagnostics.{}*.nc".format(self.y0_str)) DryDep = join(self.devdir, "*.DryDep.{}*.nc4".format(self.y0_str)) RadioNucl = join(self.devdir, "*.RadioNuclide.{}*.nc4".format(self.y0_str)) if is_gchp: StateMetAvg = join(self.devdir, "*.StateMet_avg.{}*.nc4".format(self.y0_str)) StateMetInst = join(self.devdir, "*.StateMet_inst.{}*.nc4".format(self.y0_str)) else: StateMet = join(self.devdir, "*.StateMet.{}*.nc4".format(self.y0_str)) SpeciesConc = join(self.devdir, "*.SpeciesConc.{}*.nc4".format(self.y0_str)) WetLossConv = join(self.devdir, "*.WetLossConv.{}*.nc4".format(self.y0_str)) WetLossLS = join(self.devdir, "*.WetLossLS.{}*.nc4".format(self.y0_str)) GCHPEmiss = join(self.devdir, "GCHP.Emissions.{}*.nc4".format(self.y0_str)) # ------------------------------ # Read data collections # ------------------------------ # Restarts skip_vars = constants.skip_these_vars self.ds_ini = xr.open_mfdataset(RstInit, drop_variables=skip_vars) self.ds_end = xr.open_mfdataset(RstFinal, drop_variables=skip_vars) # Change the restart datasets into format similar to GCC, and flip vertical axis if is_gchp: self.ds_ini = rename_and_flip_gchp_rst_vars(self.ds_ini) self.ds_end = rename_and_flip_gchp_rst_vars(self.ds_end) # Diagnostics self.ds_dcy = xr.open_mfdataset(RadioNucl, drop_variables=skip_vars) self.ds_dry = xr.open_mfdataset(DryDep, drop_variables=skip_vars) self.ds_cnc = xr.open_mfdataset(SpeciesConc, drop_variables=skip_vars) self.ds_wcv = xr.open_mfdataset(WetLossConv, drop_variables=skip_vars) self.ds_wls = xr.open_mfdataset(WetLossLS, drop_variables=skip_vars) # Met fields if is_gchp: self.ds_met = xr.open_mfdataset(StateMetAvg, drop_variables=skip_vars) # For now, don't read restarts for GCHP (bmy, 3/16/20) #ds_met_inst = xr.open_mfdataset(StateMetInst, # drop_variables=skip_vars) # # Add the initial met fields to the restart file collections #self.ds_ini = xr.merge([self.ds_ini, ds_met_inst.isel(time=0)]) #self.ds_end = xr.merge([self.ds_end, ds_met_inst.isel(time=11)]) else: self.ds_met = xr.open_mfdataset(StateMet, drop_variables=skip_vars) # Emissions if self.is_gchp: self.ds_hco = xr.open_mfdataset(GCHPEmiss, drop_variables=skip_vars) else: self.ds_hco = xr.open_mfdataset(HemcoDiag, drop_variables=skip_vars) # Area and troposphere mask # For gchp, get area in m2 from restart for use in calculating initial # and final mass from restart. Get area in cm2 from diagnostic # file for format compatibility with diagnostic output. if self.is_gchp: self.area_m2 = self.ds_ini["AREA"] self.area_cm2 = self.ds_met["Met_AREAM2"] * 1.0e4 else: self.area_m2 = self.ds_met["AREA"].isel(time=0) self.area_cm2 = self.area_m2 * 1.0e4 self.tropmask = get_troposphere_mask(self.ds_met) # ------------------------------ # Months and days # ------------------------------ self.N_MONTHS = 12 self.N_MONTHS_FLOAT = self.N_MONTHS * 1.0 # Days per month in the benchmark year self.d_per_mon = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.d_per_mon[t] = monthrange(self.y0, t + 1)[1] * 1.0 # Days in the benchmark year self.d_per_yr = np.sum(self.d_per_mon) # Fraction of year occupied by each month self.frac_of_yr = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.frac_of_yr[t] = self.d_per_mon[t] / self.d_per_yr # ------------------------------ # Species info # ------------------------------ # List of species (and subsets for the trop & strat) self.species_list = ["Pb210", "Be7", "Be10"] # Read the species database path = join(spcdb_dir, "species_database.yml") spcdb = yaml_load_file(open(path)) # Molecular weights [g mol-1], as taken from the species database self.mw = {} for v in self.species_list: self.mw[v] = spcdb[v]["MW_g"] self.mw["Air"] = constants.MW_AIR * 1.0e3 # kg/s --> g/day self.kg_s_to_g_d_value = 86400.0 * 1000.0 # ------------------------------ # Conversion factors # ------------------------------ self.kg_per_mol = {} self.vv_to_g = {} self.mcm2s_to_g_d = {} self.kg_s_to_g_d = {} for spc in self.species_list: # kg/s --> g/day (same for all species) self.kg_s_to_g_d[spc] = self.kg_s_to_g_d_value # kg/mole for each species self.kg_per_mol[spc] = constants.AVOGADRO / (self.mw[spc] * 1e-3) # v/v dry --> g self.vv_to_g[spc] = self.ds_met["Met_AD"].values \ * (self.mw[spc] / self.mw["Air"]) * 1000.0 # molec/cm2/s --> g/day self.mcm2s_to_g_d[spc] = self.area_cm2.values \ / self.kg_per_mol[spc] \ * self.kg_s_to_g_d[spc]
def __init__(self, devstr, maindir, plotsdir, year, overwrite): """ Initializes the _GlobVars class. Args: ----- devstr : str Label denoting the "Dev" version. maindir : str Top-level benchmark run directory. plotsdir : str Directory where plots & tables will be created. year : int Year of the benchmark simulation. overwrite : bool Denotes whether to ovewrite existing budget tables. """ # ------------------------------ # Arguments from outside # ------------------------------ self.devstr = devstr self.maindir = maindir self.plotsdir = plotsdir self.overwrite = overwrite # ------------------------------ # Benchmark year # ------------------------------ self.y0 = year self.y1 = self.y0 + 1 self.y0_str = "{}".format(self.y0) self.y1_str = "{}".format(self.y1) # ------------------------------ # Collection file lists # ------------------------------ rstdir = join(self.maindir, self.devstr, "restarts") RstInit = join(rstdir, "GEOSChem.Restart.{}*nc4".format(self.y0_str)) RstFinal = join(rstdir, "GEOSChem.Restart.{}*.nc4".format(self.y1_str)) datadir = join(self.maindir, self.devstr, "OutputDir") HemcoDiag = join(datadir, "HEMCO_diagnostics.{}*.nc".format(self.y0_str)) DryDep = join(datadir, "*.DryDep.{}*.nc4".format(self.y0_str)) RadioNucl = join(datadir, "*.RadioNuclide.{}*.nc4".format(self.y0_str)) StateMet = join(datadir, "*.StateMet.{}*.nc4".format(self.y0_str)) SpeciesConc = join(datadir, "*.SpeciesConc.{}*.nc4".format(self.y0_str)) WetLossConv = join(datadir, "*.WetLossConv.{}*.nc4".format(self.y0_str)) WetLossLS = join(datadir, "*.WetLossLS.{}*.nc4".format(self.y0_str)) GCHPEmiss = join(datadir, "GCHP.Emissions.{}*.nc4".format(self.y0_str)) # ------------------------------ # Read data collections # ------------------------------ # Restarts self.ds_ini = xr.open_mfdataset(RstInit) self.ds_end = xr.open_mfdataset(RstFinal) # Diagnostics self.ds_dcy = xr.open_mfdataset(RadioNucl) self.ds_dry = xr.open_mfdataset(DryDep) self.ds_met = xr.open_mfdataset(StateMet) self.ds_cnc = xr.open_mfdataset(SpeciesConc) self.ds_wcv = xr.open_mfdataset(WetLossConv) self.ds_wls = xr.open_mfdataset(WetLossLS) # Set a flag if this data is from GCHP self.is_gchp = "nf" in self.ds_cnc.dims.keys() # Emissions if self.is_gchp: self.ds_hco = xr.open_mfdataset(GCHPEmiss) else: self.ds_hco = xr.open_mfdataset(HemcoDiag) # Area and troposphere mask if self.is_gchp: self.area_m2 = self.ds_met["Met_AREAM2"].isel(time=0) else: self.area_m2 = self.ds_met["AREA"].isel(time=0) self.area_cm2 = self.area_m2 * 1.0e4 self.tropmask = get_troposphere_mask(self.ds_met) # ------------------------------ # Months and days # ------------------------------ self.N_MONTHS = 12 self.N_MONTHS_FLOAT = self.N_MONTHS * 1.0 # Days per month in the benchmark year self.d_per_mon = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.d_per_mon[t] = monthrange(self.y0, t+1)[1] * 1.0 # Days in the benchmark year self.d_per_yr = np.sum(self.d_per_mon) # Fraction of year occupied by each month self.frac_of_yr = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.frac_of_yr[t] = self.d_per_mon[t] / self.d_per_yr # ------------------------------ # Species info # ------------------------------ # List of species (and subsets for the trop & strat) self.species_list = ["Pb210", "Be7", "Be10" ] # Read the species database try: path = join(datadir, "species_database.yml") spcdb = yaml_load_file(open(path)) tmp = spcdb["Pb210"] except KeyError or FileNotFoundError: path = join(os.path.dirname(__file__), "species_database.yml") spcdb = yaml_load_file(open(path)) # Molecular weights [g mol-1], as taken from the species database self.mw = {} for v in self.species_list: self.mw[v] = spcdb[v]["MW_g"] self.mw["Air"] = constants.MW_AIR * 1.0e3 # kg/s --> g/day self.kg_s_to_g_d_value= 86400.0 * 1000.0 # ------------------------------ # Conversion factors # ------------------------------ self.kg_per_mol = {} self.vv_to_g = {} self.mcm2s_to_g_d = {} self.kg_s_to_g_d = {} for spc in self.species_list: # kg/s --> g/day (same for all species) self.kg_s_to_g_d[spc] = self.kg_s_to_g_d_value # kg/mole for each species self.kg_per_mol[spc] = constants.AVOGADRO / (self.mw[spc] * 1e-3) # v/v dry --> g self.vv_to_g[spc] = self.ds_met["Met_AD"].values \ * (self.mw[spc] / self.mw["Air"]) * 1000.0 # molec/cm2/s --> g/day self.mcm2s_to_g_d[spc] = self.area_cm2.values \ / self.kg_per_mol[spc] \ * self.kg_s_to_g_d[spc]
def __init__(self, devstr, devdir, devrstdir, year, dst, is_gchp, overwrite, spcdb_dir): """ Initializes the _GlobVars class. Args: devstr: str Label denoting the "Dev" version. devdir: str Directory where diagnostic files are found. devrstdir: str Directory where restart files are found. dst: str Directory where plots & tables will be created. year: int Year of the benchmark simulation. is_gchp: bool Denotes if this is GCHP (True) or GCC (False) data. overwrite: bool Denotes whether to ovewrite existing budget tables. spcdb_dir: str Directory where species_database.yml is stored. """ # ------------------------------ # Arguments from outside # ------------------------------ self.devstr = devstr self.devdir = devdir self.devrstdir = devrstdir self.dst = dst self.is_gchp = is_gchp self.overwrite = overwrite # ------------------------------ # Benchmark year # ------------------------------ self.y0 = year self.y1 = self.y0 + 1 self.y0_str = "{}".format(self.y0) self.y1_str = "{}".format(self.y1) # ------------------------------ # Collection file lists # ------------------------------ # Restarts if self.is_gchp: RstInit = join(self.devrstdir, "initial_GEOSChem_rst.c48_TransportTracers.nc") RstFinal = join( self.devrstdir, "gcchem_internal_checkpoint.restart.{}*.nc4".format( self.y1_str)) else: RstInit = join(self.devrstdir, "GEOSChem.Restart.{}*nc4".format(self.y0_str)) RstFinal = join(self.devrstdir, "GEOSChem.Restart.{}*.nc4".format(self.y1_str)) # Diagnostics HemcoDiag = join(self.devdir, "HEMCO_diagnostics.{}*.nc".format(self.y0_str)) DryDep = join(self.devdir, "*.DryDep.{}*.nc4".format(self.y0_str)) RadioNucl = join(self.devdir, "*.RadioNuclide.{}*.nc4".format(self.y0_str)) if is_gchp: StateMetAvg = join(self.devdir, "*.StateMet_avg.{}*.nc4".format(self.y0_str)) StateMet = join(self.devdir, "*.StateMet.{}*.nc4".format(self.y0_str)) # Set a logical if we need to read StateMet_avg or StateMet gchp_use_statemet_avg = os.path.exists(StateMetAvg) else: StateMet = join(self.devdir, "*.StateMet.{}*.nc4".format(self.y0_str)) SpeciesConc = join(self.devdir, "*.SpeciesConc.{}*.nc4".format(self.y0_str)) WetLossConv = join(self.devdir, "*.WetLossConv.{}*.nc4".format(self.y0_str)) WetLossLS = join(self.devdir, "*.WetLossLS.{}*.nc4".format(self.y0_str)) GCHPEmiss = join(self.devdir, "*.Emissions.{}*.nc4".format(self.y0_str)) # ------------------------------ # Read data collections # ------------------------------ # Restarts skip_vars = constants.skip_these_vars extra_kwargs = {} self.ds_ini = xr.open_mfdataset(RstInit, drop_variables=skip_vars, **extra_kwargs) self.ds_end = xr.open_mfdataset(RstFinal, drop_variables=skip_vars, **extra_kwargs) # Change the restart datasets into format similar to GCC, and flip # vertical axis. Also test if the restart files have the BXHEIGHT # variable contained within them. if is_gchp: self.ds_ini = rename_and_flip_gchp_rst_vars(self.ds_ini) self.ds_end = rename_and_flip_gchp_rst_vars(self.ds_end) # Diagnostics self.ds_dcy = xr.open_mfdataset(RadioNucl, drop_variables=skip_vars, **extra_kwargs) self.ds_dry = xr.open_mfdataset(DryDep, drop_variables=skip_vars, **extra_kwargs) self.ds_cnc = xr.open_mfdataset(SpeciesConc, drop_variables=skip_vars, **extra_kwargs) self.ds_wcv = xr.open_mfdataset(WetLossConv, drop_variables=skip_vars, **extra_kwargs) self.ds_wls = xr.open_mfdataset(WetLossLS, drop_variables=skip_vars, **extra_kwargs) # Met fields # For GCHP: Read from StateMet_avg if present (otherwise StateMet) if is_gchp and gchp_use_statemet_avg: self.ds_met = xr.open_mfdataset(StateMetAvg, drop_variables=skip_vars, **extra_kwargs) else: self.ds_met = xr.open_mfdataset(StateMet, drop_variables=skip_vars, **extra_kwargs) # Emissions if self.is_gchp: self.ds_hco = xr.open_mfdataset(GCHPEmiss, drop_variables=skip_vars, **extra_kwargs) else: self.ds_hco = xr.open_mfdataset(HemcoDiag, drop_variables=skip_vars, **extra_kwargs) # Area and troposphere mask # The area in m2 is on the restart file grid # The area in cm2 is on the History diagnostic grid # Both grids are identical in GCClassic but differ in GCHP if self.is_gchp: if 'Met_AREAM2' not in self.ds_met.data_vars.keys(): msg = 'Could not find Met_AREAM2 in StateMet_avg collection!' raise ValueError(msg) area_m2 = self.ds_met["Met_AREAM2"].isel(time=0) area_m2 = reshape_MAPL_CS(area_m2) self.area_m2 = area_m2 self.area_cm2 = self.ds_met["Met_AREAM2"] * 1.0e4 else: self.area_m2 = self.ds_met["AREA"].isel(time=0) self.area_cm2 = self.area_m2 * 1.0e4 self.tropmask = get_troposphere_mask(self.ds_met) # ------------------------------ # Months and days # ------------------------------ self.N_MONTHS = 12 self.N_MONTHS_FLOAT = self.N_MONTHS * 1.0 # Days per month in the benchmark year self.d_per_mon = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.d_per_mon[t] = monthrange(self.y0, t + 1)[1] * 1.0 # Days in the benchmark year self.d_per_yr = np.sum(self.d_per_mon) # Fraction of year occupied by each month self.frac_of_yr = np.zeros(self.N_MONTHS) for t in range(self.N_MONTHS): self.frac_of_yr[t] = self.d_per_mon[t] / self.d_per_yr # ------------------------------ # Species info # ------------------------------ # List of species (and subsets for the trop & strat) self.species_list = ["Pb210", "Be7", "Be10"] # Read the species database path = join(spcdb_dir, "species_database.yml") spcdb = yaml_load_file(open(path)) # Molecular weights [g mol-1], as taken from the species database self.mw = {} for v in self.species_list: self.mw[v] = spcdb[v]["MW_g"] self.mw["Air"] = constants.MW_AIR_g # kg/s --> g/day self.kg_s_to_g_d_value = 86400.0 * 1000.0 # ------------------------------ # Conversion factors # ------------------------------ self.kg_per_mol = {} self.vv_to_g = {} self.mcm2s_to_g_d = {} self.kg_s_to_g_d = {} for spc in self.species_list: # kg/s --> g/day (same for all species) self.kg_s_to_g_d[spc] = self.kg_s_to_g_d_value # kg/mole for each species self.kg_per_mol[spc] = constants.AVOGADRO / (self.mw[spc] * 1e-3) # v/v dry --> g self.vv_to_g[spc] = self.ds_met["Met_AD"].values \ * (self.mw[spc] / self.mw["Air"]) * 1000.0 # molec/cm2/s --> g/day self.mcm2s_to_g_d[spc] = self.area_cm2.values \ / self.kg_per_mol[spc] \ * self.kg_s_to_g_d[spc]