text: # -*- coding: utf-8 -*-
  # BioSTEAM: The Biorefinery Simulation and Techno-Economic Analysis Modules
  # Copyright (C) 2020, Yoel Cortes-Pena <yoelcortes@gmail.com>
  # 
  # This module is under the UIUC open-source license. See 
  # github.com/BioSTEAMDevelopmentGroup/biosteam/blob/master/LICENSE.txt
  # for license details.
  """
  This module defines the composition_balance function, which performs mass 
  energy balance the given oil composition of lipid cane to determine its
  composition.
  
  """
  from thermosteam import Stream
  from biorefineries import lipidcane as lc
  from numpy import array
  
  __all__ = ('set_lipid_fraction',
             'get_lipid_fraction')
  
  def set_lipid_fraction(lipid_fraction, stream=None, data={}):
      """Adjust composition of lipid cane to achieve desired oil fraction (dry weight)."""
      if not stream: stream = lc.lipidcane
      if not data:
          carbs_IDs = ('Glucose', 'Sucrose')
          fiber_IDs = ('Lignin', 'Cellulose', 'Hemicellulose')
          lipid_IDs = ('Lipid',)
          
          carbs   = Stream('Carbs', thermo=stream.thermo)
          fiber   = Stream('Fiber', thermo=stream.thermo)
          lipid   = Stream('Lipid', thermo=stream.thermo)
          carbs.imol[carbs_IDs] = stream.imol[carbs_IDs]
          fiber.imol[fiber_IDs] = stream.imol[fiber_IDs]
          lipid.imol[lipid_IDs] = stream.imol[lipid_IDs]
          
          # Mass property arrays
          carbs_mass = stream.imass[carbs_IDs]
          fiber_mass = stream.imass[fiber_IDs]
          lipid_mass = stream.imass[lipid_IDs]
          
          # Net weight
          carbs_massnet = carbs_mass.sum()
          fiber_massnet = fiber_mass.sum()
          lipid_massnet = lipid_mass.sum()
          
          # Heats of combustion per kg
          LHV_carbs_kg = carbs.LHV/carbs_massnet
          LHV_lipid_kg = lipid.LHV/lipid_massnet
          data['LHV_lipid_over_carbs'] = LHV_lipid_kg / LHV_carbs_kg
          
          
          # Relative composition
          data['r_mass_carbs'] = array(carbs_mass/carbs_massnet)
          data['r_mass_fiber'] = array(fiber_mass/fiber_massnet)
          
      z_mass_lipid = lipid_fraction
      F_mass = stream.F_mass
      z_dry = 0.3
      z_mass_lipid = z_mass_lipid * z_dry 
      z_mass_carbs = 0.149 - z_mass_lipid * data['LHV_lipid_over_carbs']
      z_mass_fiber = z_dry - z_mass_carbs - z_mass_lipid - 0.006 - 0.015
      imass = stream.imass
      imass['Water'] = F_mass*0.7
      imass['Ash'] = F_mass*0.006
      imass['Solids'] = F_mass*0.015
      imass['Lipid'] = z_mass_lipid * F_mass
      imass['Glucose', 'Sucrose'] = data['r_mass_carbs'] * z_mass_carbs * F_mass
      imass['Lignin', 'Cellulose', 'Hemicellulose'] = data['r_mass_fiber'] * z_mass_fiber * F_mass
      if any(stream.mol < 0):
          raise ValueError(f'lipid cane oil composition of {z_mass_lipid*100:.0f}% dry weight is infeasible')
  
  def get_lipid_fraction(stream=None):
      if not stream: stream = lc.lipidcane
      imass = stream.imass
      F_dry_mass = stream.F_mass - imass['Water']
      return imass['Lipid'] / F_dry_mass