Tests Ruby Gem Gem Version

LCA

Storing, processing and working with life-cycle assessment data has always been challenging. A multitude of data models and implementations exist already but every one of them makes huge compromises or lacks functionality.

This gem implements a denormalized database model for life-cycle assessment data as well as several vectors for convenient querying.

Installation

This gem is at home within a Rails 6+ console-only, API or full fledged application on top of a Postgres database.

Add this line to your application's Gemfile:

gem 'lca'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install lca

Upon installing the gem you must run the ActiveTree install process in your Rails application's root:

$ rails g active_tree:install

This will generate a config/active_tree.yml which you may customize to your needs, an initializer and a migration file which you can also customize to add any database columns your models will require.

You must also run the LCA gem install generator:

$ rails g lca:install

This will create a migration file which you can edit to add your models' specific attributes.

Usage

Include the ActiveTree concern into one of your models which will own lifecycle trees (owner model):

    class User < ApplicationRecord
        include Lca::Lcable
        # ...
    end

This will extend your model and enable the following functionality:

# query with ActiveRecord syntax
User.last.active_trees
User.find_by(name: "Acme").active_trees.impacts.select("impact_unit, sum(impact_amount) as total_impact").group(:impact_unit)
User.last.active_trees.where(...)
User.last.active_trees.where(...).group(...)
User.last.active_trees.where(...).limit(...).offset(...)

# AR query with ltree syntax
User.last.active_trees.disabled.match_path("*.CustomProcess.*")
User.last.active_trees.match_path("*{5,10}.CustomProcess.*.Ecosphere.*")
User.last.active_trees.active.match_path("*.WhateverProcess.*.Ecosphere.*.CO2Emission.*").where( impact_amount: [100..150]).sum(:impact_amount)

Lca::Cycle.match_path("Top.Electric Vehicle.*").impacts.match_path("*.CO2*").where( impact_amount: [ 1000..10000 ]).average(:impact_amount)
Lca::Cycle::Product.where(name: "Electric Vehicle Battery").impacts.match_path("*.Cobalt.*").sum(:impact_amount)
Lca::Process.where(owner: User.last).match_path("*{10,20}.*Assembly, automated.*")
Lca::Impact.match_path("*.Transport by truck.*")
Lca::Exchange.match_path("*.Oil.*.Ecosphere.*").impacts.sum(:impact_amount)
Lca::Product.match_path("*.ElectricVehicle.*").processes.match_path("*.Processing.*").where(location: "EU").impacts.match_path("*.Lithium.*").where(location: ["CN", "Africa"]).sum(:impact_amount)

# pg_ltree queries
User.last.active_trees.last.parent
Lca::Process.match_path("*.Manual assembly.*").children

# pg_ltree combined with AR syntax
User.last.active_trees(type: "Lca::Product").children.match_path("*.Retail").children.exchanges

# all queries can be directed to a specific partition:
Lca::Process.owned_by( owner_id ).match_path("*.Recycling.*").where(impact_unit: "tons CO2/year").impacts.sum(:impact_amount)

The gem also creates some default models:

Lca::Process::Transport::ByAir.match_path("*.CO2Emission.*").impacts.sum(:impact_amount)
Lca::Impact::Ecosphere::Fauna.match_path("*.ResourceExtraction.*").where(impact_unit: "Species killed/year").sum(:impact_amount)

To see what syntax to use for path traversal please check out the following resources:

Scalability

All LCA data can be stored into separate partitions using the ActiveTree partitioning feature. See config/active_tree.yml for table and partitioning naming and options.

Caveats

pg_ltree .child / .parent queries do not work across different models due to an ActiveRecord limitation that requires results to be related via inheritance.

The following behaviors have been observed:


Lca::Process.last.children.impacts.where(impact_amount: 50)
# => nil

Lca::Process.last.children.unscope(where: :type).impacts.where(impact_amount: 50)
# => ActiveRecord::SubclassNotFound (Invalid single-table inheritance type: Lca::Impact is not a subclass of Lca::Process)

Roadmap

  • .child / .parent query support across models unrelated through inheritance
  • more model templates for various LCA cycles, processes and impacts
  • model validations
  • postgres RECURSIVE queries
  • builders
  • seeds/fixtures

Contributing

Bug reports, pull requests and feature suggestions are welcome on GitHub at https://github.com/nicksterious/lca

License

The gem is available as open source under the terms of the MIT License.