Source code for chemics.biomass_composition

"""
Functions for biomass composition.
"""

import numpy as np


[docs] def biocomp( yc, yh, yo=None, yh2o=0, yash=0, alpha=0.6, beta=0.8, gamma=0.8, delta=1, epsilon=1, printcomp=False, ): """ Biomass composition. Determine bimoass composition from ultimate analysis mass fractions of C, H, and O. Composition returned as cellulose, hemicellulose, lignins, and extractives based on method discussed in the Debiagi 2015 paper [1]_. Parameters ---------- yc : float Mass fraction of carbon in biomass, dry ash free basis yh : float Mass fraction of hydrogen in biomass, dry ash free basis yo : float, optional Mass fraction of oxygen in biomass, if not given then value is calculated as difference, dry ash free basis. Default is None. yh2o : float, optional Mass fraction of water in biomass, as received basis. Default is 0. yash : float, optional Mass fraction of ash in biomass, as received basis. Default is 0. alpha : float, optional Splitting parameter as molar ratio of cellulose and hemicellulose contained in reference mixture RM1. Default is 0.6. beta : float, optional Splitting parameter as molar ratio of lignin LIG-O and lignin LIG-C contained in reference mixture RM2. Default is 0.8. gamma : float, optional Splitting parameter as molar ratio of lignin LIG-H and lignin LIG-C contained in reference mixture RM3. Default is 0.8. delta : float, optional Splitting parameter as molar ratio of lignins (LIG-H and LIG-C) and extractive TGL to define reference mixture RM2. Default is 1.0. epsilon : float, optional Splitting parameter as molar ratio of lignins (LIG-O and LIG-C) and extractive TANN to define reference mixture RM3. Default is 1.0. printcomp : bool, optional Print composition results if True. Default is False. Returns ------- comp : dict Dictionary representing reference mixtures and biomass compositions on the basis of mole fractions (x) and mass fractions (y). The dictionary contains the following items for the reference mixtures where each item represents the C, H, O mass fraction. - `y_rm1` reference mixture RM1 - `y_rm2` reference mixture RM2 - `y_rm3` reference mixture RM3 The dictionary also contains the following items for the biomass composition where each item represents the CELL, HEMI, LIGC, LIGH, LIGO, TANN, TGL mole or mass fraction. - `x_daf` mole fractions as dry ash-free basis - `x_wet` mole fractions as wet basis - `y_daf` mass fractions as dry ash-free basis - `y_wet` mass fractions as wet basis - `y_wetash` mass fractions as wet + ash basis Raises ------ ValueError When sum of mass fractions is not equal to one. Examples -------- Use the carbon and hydrogen mass fractions of the biomass to calculate the biomass composition. >>> yc = 0.534 >>> yh = 0.06 >>> bc = cm.biocomp(yc, yh) The cellulose mass fraction on a dry ash-free basis. >>> cell = bc['y_daf'][0] >>> cell 0.293... The hemicellulose mass fraction on a dry ash-free basis. >>> hemi = bc['y_daf'][1] >>> hemi 0.159... References ---------- .. [1] Paulo Eduardo Amaral Debiagi, Chiara Pecchi, Giancarlo Gentile, Alessio Frassoldati, Alberto Cuoci, Tiziano Faravelli, and Eliseo Ranzi. Extractives Extend the Applicability of Multistep Kinetic Scheme of Biomass Pyrolysis. Energy and Fuels, vol. 29, no. 10, pp. 6544-6555, 2015. """ # Determine oxygen mass fraction by difference if not explicitly given if yo is None: yo = 1 - yc - yh # Check that mass fractions sum to one sumy = yc + yh + yo tol = 1e-4 if abs(sumy - 1.0) > tol: raise ValueError("Sum of mass fractions must equal one.") # Cellulose, hemicellulose, and lignins as arrays of [C, H, O] # See Figure 1 in reference for these formulas cell = np.array([6, 10, 5]) hemi = np.array([5, 8, 4]) ligc = np.array([15, 14, 4]) ligh = np.array([22, 28, 9]) ligo = np.array([20, 22, 10]) tann = np.array([15, 12, 7]) tgl = np.array([57, 100, 7]) # Molecular weight of cellulose, hemicellulose, lignins, and water mw_cell = 162.141 mw_hemi = 132.115 mw_ligc = 258.273 mw_ligh = 436.457 mw_ligo = 422.386 mw_tann = 304.254 mw_tgl = 897.42 mw_h2o = 18.015 # Solve for pseudo species # ----------------------------------------------------------------------- # Reference mixture where rm = [C, H, O] rm1 = alpha * cell + (1 - alpha) * hemi rm2 = ( beta * delta * ligh + (1 - beta) * delta * ligc + (1 - beta * delta - (1 - beta) * delta) * tgl ) rm3 = ( gamma * epsilon * ligo + (1 - gamma) * epsilon * ligc + (1 - gamma * epsilon - (1 - gamma) * epsilon) * tann ) # Molecular weight of reference mixture where C, H, O given as 12, 1, 16 mw_rm1 = sum(rm1 * [12, 1, 16]) mw_rm2 = sum(rm2 * [12, 1, 16]) mw_rm3 = sum(rm3 * [12, 1, 16]) # Mass fraction of reference mixture where y_rm = [yC, yH, yO] y_rm1 = (rm1 * [12, 1, 16]) / mw_rm1 y_rm2 = (rm2 * [12, 1, 16]) / mw_rm2 y_rm3 = (rm3 * [12, 1, 16]) / mw_rm3 # Mass fraction of pseudo species where ys = [S1, S2, S3] # Solve system of linear equations Ax = b # A is 3x3 matrix with columns = [yC, yH, yO] a = np.array([y_rm1, y_rm2, y_rm3]).T b = np.array([yc, yh, yo]) ys = np.linalg.solve(a, b) # Sum of mass fractions and molecular weights as sum(ys/MW) sum_ymw = sum(ys / [mw_rm1, mw_rm2, mw_rm3]) # Mole fraction of pseudo species where xs = [S1, S2, S3] xs = (ys / [mw_rm1, mw_rm2, mw_rm3]) / sum_ymw # Biomass composition # ----------------------------------------------------------------------- # Mole fraction as dry ash free basis for biomass components where # x_daf = [cell, hemi, ligc, ligh, ligo, tann, tgl] x_dafcell = alpha * xs[0] x_dafhemi = (1 - alpha) * xs[0] x_dafligc = (1 - beta) * delta * xs[1] + (1 - gamma) * epsilon * xs[2] x_dafligh = beta * delta * xs[1] x_dafligo = gamma * epsilon * xs[2] x_daftann = (1 - gamma * epsilon - (1 - gamma) * epsilon) * xs[2] x_daftgl = (1 - beta * delta - (1 - beta) * delta) * xs[1] x_daf = np.array([x_dafcell, x_dafhemi, x_dafligc, x_dafligh, x_dafligo, x_daftann, x_daftgl]) # Molecular weight vector for biomass components where # mw_comp = [mw_cell, mw_hemi, mw_ligc, mw_ligh, mw_ligo, mw_tann, mw_tgl] mw_comp = x_daf * [mw_cell, mw_hemi, mw_ligc, mw_ligh, mw_ligo, mw_tann, mw_tgl] # Average molecular weight of all biomass components mw_avg = sum(mw_comp) # Mass fraction as dry ash free basis for biomass components where # y_daf = [cell, hemi, ligc, ligh, ligo, tann, tgl] y_daf = mw_comp / mw_avg # Mass fraction as wet basis for biomass components where # y_wet = [cell, hemi, ligc, ligh, ligo, tann, tgl] y_wet = y_daf * (1 - yh2o) # Mass fraction as wet + ash basis for biomass components where # y_wetash = [cell, hemi, ligc, ligh, ligo, tann, tgl] y_wetash = y_daf * (1 - yh2o - yash) # Mole fraction as wet basis for biomass components where # x_wet = [cell, hemi, ligc, ligh, ligo, tann, tgl] ywet_yh2o = np.concatenate((y_wet, [yh2o])) sum_xmw = sum( ywet_yh2o / [mw_cell, mw_hemi, mw_ligc, mw_ligh, mw_ligo, mw_tann, mw_tgl, mw_h2o] ) x_wet = (y_wet / [mw_cell, mw_hemi, mw_ligc, mw_ligh, mw_ligo, mw_tann, mw_tgl]) / sum_xmw comp = { "y_rm1": y_rm1, "y_rm2": y_rm2, "y_rm3": y_rm3, "x_daf": x_daf, "x_wet": x_wet, "y_daf": y_daf, "y_wet": y_wet, "y_wetash": y_wetash, } # Print biomass composition results if printcomp: print("basis\t cell\t hemi\t ligc\t ligh\t ligo\t tann\t tgl") print("x_daf\t", " ".join(f"{x:.4f}" for x in x_daf)) print("x_wet\t", " ".join(f"{x:.4f}" for x in x_wet)) print("y_daf\t", " ".join(f"{x:.4f}" for x in y_daf)) print("y_wet\t", " ".join(f"{x:.4f}" for x in y_wet)) print("y_wetash", " ".join(f"{x:.4f}" for x in y_wetash)) return comp
[docs] def plot_biocomp(ax, yc, yh, y_rm1, y_rm2, y_rm3): """ Plot biomass composition. Plot characterization of biomass sample and calculated reference mixtures as mass fractions, dry ash-free basis. Parameters ---------- ax : Axes The Matplotlib axes from a figure yc : float Mass fraction of carbon in biomass, dry ash free basis yh : float Mass fraction of hydrogen in biomass, dry ash free basis y_rm1 : array Mass fraction of reference mixture RM1 where y_rm1 = [yC, yH, yO] y_rm2 : array Mass fraction of reference mixture RM2 where y_rm2 = [yC, yH, yO] y_rm3 : array Mass fraction of reference mixture RM3 where y_rm3 = [yC, yH, yO] Returns ------- ax : Axes The Matplotlib axes for the plot figure """ ax.plot(yc, yh, "^", label="biomass") ax.plot(0.4444, 0.0617, "o") ax.annotate("cell", xy=(0.4444, 0.0617), xytext=(-10, 6), textcoords="offset points") ax.plot(0.4545, 0.0606, "o") ax.annotate("hemi", xy=(0.4545, 0.0606), xytext=(-10, -12), textcoords="offset points") ax.plot(0.6977, 0.0543, "o") ax.annotate("ligc", xy=(0.6977, 0.0543), xytext=(-10, -12), textcoords="offset points") ax.plot(0.6055, 0.0642, "o") ax.annotate("ligh", xy=(0.6055, 0.0642), xytext=(-10, 6), textcoords="offset points") ax.plot(0.5687, 0.0521, "o") ax.annotate("ligo", xy=(0.5687, 0.0521), xytext=(-10, -12), textcoords="offset points") ax.plot(0.5921, 0.0395, "o") ax.annotate("tann", xy=(0.5921, 0.0395), xytext=(-10, -12), textcoords="offset points") ax.plot(0.7634, 0.1116, "o") ax.annotate("tgl", xy=(0.7634, 0.1116), xytext=(-6, -12), textcoords="offset points") x = 0.4444, 0.5921, 0.6977, 0.7634 y = 0.0617, 0.0395, 0.0543, 0.1116 ax.fill(x, y, "0.8", alpha=0.5) ax.plot(y_rm1[0], y_rm1[1], "s", label="rm1") ax.plot(y_rm2[0], y_rm2[1], "s", label="rm2") ax.plot(y_rm3[0], y_rm3[1], "s", label="rm3") x = y_rm1[0], y_rm2[0], y_rm3[0], y_rm1[0] y = y_rm1[1], y_rm2[1], y_rm3[1], y_rm1[1] ax.plot(x, y, "k:") ax.grid(color="0.9") ax.set_axisbelow(True) ax.set_frame_on(False) ax.set_xlabel("Carbon mass fraction, daf basis [-]") ax.set_ylabel("Hydrogen mass fraction, daf basis [-]") ax.tick_params(color="0.9") ax.legend(frameon=False) return ax