class Quantify::Dimensions

The Dimensions class represents specfic physical quantities in terms of powers of their constituent base dimensions, e.g.:

area = length^2 force = mass^1 x length^1 x time^-2

Each dimension object is characterised by instance variables which describe the power (or index) of the respective base dimensions. Dimension objects can be manipulated - multiplied, divided, raised to powers, etc.

Standard physical quantities (e.g. length, acceleration, energy) are loaded into the @@dimensions class variable at runtime. These can be accessed, used and manipulated for arbitrary dimensional uses.

Instances of Dimensions are also used as the basis for defining and manipulating objects of the Unit::Base class.

Constants

BASE_QUANTITIES

The BASE_QUANTITIES array specifies the system of base quantities upon which all Dimensions objects are defined.

:information, :currency, :item represent tentative additions to the standard set of base quantities.

:item is intended to represent arbitrary 'things' for specifying quantities such as, for example:

'dollars per capita' (:currency => 1, :items => -1) 'trees per hectare' (:items => 1, :length => -2).

Attributes

physical_quantity[RW]

Public Class Methods

base_dimensions() click to toggle source

Returns an array of Dimensions objects representing just the base quantities, i.e. length, mass, time, temperature, etc.

# File lib/quantify/dimensions.rb, line 52
def self.base_dimensions
  @@dimensions.select do |dimensions|
    BASE_QUANTITIES.map {|quantity| quantity.remove_underscores}.include?(dimensions.describe)
  end
end
configure(&block) click to toggle source

Syntactic sugar for defining the known quantities. This method simply evaluates code within the context of the Dimensions class, enabling the required quantities to be loaded at runtime, e.g.

Dimensions.configure do

  load :physical_quantity => :length, :length => 1
  load :physical_quantity => :area, :length => 2
  load :physical_quantity => :power, :mass => 1, :length => 2, :time => -3

end
# File lib/quantify/dimensions.rb, line 142
def self.configure(&block)
    self.class_eval(&block) if block
end
dimensions() click to toggle source

Provides access the class array which holds all defined quantities

# File lib/quantify/dimensions.rb, line 45
def self.dimensions
  @@dimensions
end
for(name) click to toggle source

Retrieve a known quantity - returns a Dimensions instance, which is a clone of the initialized instance of the specified quantity. This enables the object to be modified/manipulated without corrupting the representation of the quantity in the @@dimensions class array.

The required quantity name/descriptor can be specified as a symbol or a string, e.g.:

Dimensions.for :acceleration
Dimensions.for 'luminous_flux'

These can be shortened to, e.g. Dimensions.acceleration by virtue of the method_missing class method (below)

# File lib/quantify/dimensions.rb, line 116
def self.for(name)
  return name if name.is_a? Dimensions
  if (name.is_a?(String) || name.is_a?(Symbol))
    name = name.remove_underscores.downcase
    if quantity = @@dimensions.find { |quantity| quantity.physical_quantity == name }
      return quantity.clone
    else
      raise Exceptions::InvalidArgumentError, "Physical quantity not known: #{name}"
    end
  else
    raise Exceptions::InvalidArgumentError, "Argument must be a Symbol or String"
  end
end
load(options) click to toggle source

This method allows specific, named quantities to be initialized and loaded into the @@dimensions array. Quantities are specified by their consituent base dimensions, but must also include a name/description, i.e. 'acceleration', :force - indicated by the :physical_quantity key - in order to be included in the system of known dimensions, e.g.:

Dimensions.load :physical_quantity => :force,
                :length => 1,
                :mass => 1,
                :time => -2

Standard quantities such as force, energy, mass, etc. should not need to be defined as they are included in the set of quantities already defined (see config.rb) and automatically loaded. These can be removed, overridden or configured differently if desired.

# File lib/quantify/dimensions.rb, line 74
def self.load(options)
  if options[:physical_quantity]
    @@dimensions << Dimensions.new(options)
  else
    raise Exceptions::InvalidDimensionError, "Cannot load dimensions without physical quantity description"
  end
end
method_missing(method, *args, &block) click to toggle source

Provides a shorthand for retrieving known quantities, e.g.:

Dimensions.force

is equivalent to

Dimensions.for :force

Both variants return a clone of the initialized dimensional representation of the specified physical quantity (i.e. force).

Calls superclass method
# File lib/quantify/dimensions.rb, line 157
def self.method_missing(method, *args, &block)
  if dimensions = self.for(method)
    return dimensions
  end
  super
end
new(options={}) click to toggle source

Initialize a new Dimension object.

The options argument is a hash which represents the base dimensions that define the physical quantity. Each key-value pair should consist of a key included in the BASE_QUANTITIES array, and a value which represents the index/power of that base quantity.

In addition, a name or description of the physical quantity can be specified (i.e. 'acceleration', 'electric_current'). This is optional for creating a new Dimensions instance, but required if that object is to be loaded into the @@dimensions class array. e.g.:

Dimensions.new :physical_quantity => :density,
               :mass => 1,
               :length => -3
# File lib/quantify/dimensions.rb, line 184
def initialize(options={})
  if options.has_key?(:physical_quantity)
    @physical_quantity = options.delete(:physical_quantity).remove_underscores.downcase
  end
  enumerate_base_quantities(options)
  describe
end
physical_quantities() click to toggle source

Returns an array containing the names/descriptions of all known (loaded) physical quantities, e.g.:

Dimensions.physical_quantities     #=>    [ 'acceleration',
                                            'area',
                                            'electric Current',
                                             ... ]
# File lib/quantify/dimensions.rb, line 98
def self.physical_quantities
  @@dimensions.map {|dimension| dimension.physical_quantity }
end
unload(*unloaded_dimensions) click to toggle source

Remove a dimension from the system of known dimensions

# File lib/quantify/dimensions.rb, line 83
def self.unload(*unloaded_dimensions)
  [unloaded_dimensions].flatten.each do |unloaded_dimension|
    unloaded_dimension = Dimensions.for(unloaded_dimension)
    @@dimensions.delete_if { |dimension| dimension.has_same_identity_as? unloaded_dimension }
  end
end

Public Instance Methods

*(other)
Alias for: multiply
**(power)
Alias for: pow
/(other)
Alias for: divide
==(other) click to toggle source

Compares the base quantities of two Dimensions objects and returns true if they are the same. This indicates that the two objects represent the same physical quantity (irrespective of their names - @physical_quantity - being similar, different, or absent.

# File lib/quantify/dimensions.rb, line 330
def ==(other)
  self.to_hash == other.to_hash
end
describe() click to toggle source

Return a description of what physical quantity self represents. If no value is found in the @physical_quantity instance variable, the task is delegated to the get_description method.

# File lib/quantify/dimensions.rb, line 226
def describe
  @physical_quantity or get_description
end
divide(other) click to toggle source

Similar to divide! but returns a new Dimensions instance representing the physical quantity which results from the division.

# File lib/quantify/dimensions.rb, line 399
def divide(other)
  Dimensions.new(self.to_hash).divide! other
end
Also aliased as: /
divide!(other) click to toggle source

Similar to multiply! but performs a division of self by the specified Dimensions object.

# File lib/quantify/dimensions.rb, line 390
def divide!(other)
  enumerate_base_quantities(other.reciprocalize.to_hash)
  get_description
  return self
end
get_description() click to toggle source

Searches the system of known physical quantities (@@dimensions class array) looking for any which match self in terms of the configuration of base dimensions, i.e. an object which dimensionally represents the same thing.

If found, the name/description of that quantity is assigned to the @physical_quantity attribute of self.

This method is useful in cases where Dimensions instances are manipulated using operators (e.g. multiply, divide, power, reciprocal), resulting in a change to the configuration of base dimensions (perhaps as a new instance). This method tries to find a description of the new quantity.

If none is found, self.physical_quantity is set to nil.

# File lib/quantify/dimensions.rb, line 245
def get_description
  similar = @@dimensions.find { |quantity| quantity == self }
  @physical_quantity = similar.nil? ? nil : similar.physical_quantity
end
has_same_identity_as?(other) click to toggle source
# File lib/quantify/dimensions.rb, line 218
def has_same_identity_as?(other)
  @physical_quantity == other.physical_quantity && !@physical_quantity.nil?
end
is_base?() click to toggle source

Returns true if self represents one of the base quantities (i.e. length, mass, time, etc.)

# File lib/quantify/dimensions.rb, line 346
def is_base?
  base_quantities.size == 1 &&
    self.instance_variable_get(base_quantities.first) == 1 ? true : false
end
is_dimensionless?() click to toggle source

Returns true if self is a dimensionless quantity

# File lib/quantify/dimensions.rb, line 340
def is_dimensionless?
  base_quantities.empty?
end
is_known?() click to toggle source

Returns true if the physical quantity that self represents is known

# File lib/quantify/dimensions.rb, line 335
def is_known?
  describe ? true : false
end
is_molar_quantity?() click to toggle source

Method for identifying quantities which are 'molar' quantities, i.e quantities which represent a quantity of something *per mole*

# File lib/quantify/dimensions.rb, line 361
def is_molar_quantity?
  denominator_quantities == [:@amount_of_substance]
end
is_specific_quantity?() click to toggle source

Method for identifying quantities which are 'specific' quantities, i.e quantities which represent a quantity of something *per unit mass*

# File lib/quantify/dimensions.rb, line 354
def is_specific_quantity?
  denominator_quantities == [:@mass]
end
load() click to toggle source

Load an already instantiated Dimensions object into the @@dimensions class array, from which it will be accessible as a universal representation of that physical quantity.

Object must include a non-nil @physical_quantity attribute, i.e. a name or description of the physical quantity represented.

# File lib/quantify/dimensions.rb, line 199
def load
  if describe && !loaded?
    @@dimensions << self
  elsif describe
    raise Exceptions::InvalidDimensionError, "A dimension instance with the same physical quantity already exists"
  else
    raise Exceptions::InvalidDimensionError, "Cannot load dimensions without physical quantity description"
  end
end
loaded?() click to toggle source
# File lib/quantify/dimensions.rb, line 209
def loaded?
  Dimensions.dimensions.any? { |quantity| self.has_same_identity_as? quantity }
end
multiply(other) click to toggle source

Similar to multiply! but returns a new Dimensions instance representing the physical quantity which results from the multiplication.

# File lib/quantify/dimensions.rb, line 381
def multiply(other)
  Dimensions.new(self.to_hash).multiply! other
end
Also aliased as: times, *
multiply!(other) click to toggle source

Multiplies self by another Dimensions object, returning self with an updated configuration of dimensions. Since this is likely to have resulted in the representation of a different physical quantity than was originally represented, the get_description method is invoked to attempt to find a suitable description.

# File lib/quantify/dimensions.rb, line 372
def multiply!(other)
  enumerate_base_quantities(other.to_hash)
  get_description
  return self
end
pow(power) click to toggle source

Similar to pow! but returns a new Dimensions instance representing the physical quantity which results from the raised power.

# File lib/quantify/dimensions.rb, line 423
def pow(power)
  Dimensions.new(self.to_hash).pow!(power)
end
Also aliased as: **
pow!(power) click to toggle source

Raises self to the power provided. As with multiply and divide, the get_description method is invoked to attempt to find a suitable description for the new quantity represented.

# File lib/quantify/dimensions.rb, line 408
def pow!(power)
  make_dimensionless if power == 0
  if power < 0
    self.reciprocalize!
    power *= -1
  end
  original_dimensions = self.clone
  (power - 1).times { self.multiply!(original_dimensions) }
  get_description
  return self
end
reciprocalize() click to toggle source

Similar to reciprocalize! but returns a new Dimensions instance representing the physical quantity which results from the inversion.

# File lib/quantify/dimensions.rb, line 444
def reciprocalize
  Dimensions.new(self.to_hash).reciprocalize!
end
reciprocalize!() click to toggle source

Inverts self, returning a representation of 1/self. This is equivalent to raising to the power -1. The get_description method is invoked to attempt to find a suitable description for the new quantity represented.

# File lib/quantify/dimensions.rb, line 432
def reciprocalize!
  base_quantities.each do |variable|
    new_value = self.instance_variable_get(variable) * -1
    self.instance_variable_set(variable, new_value)
  end
  get_description
  return self
end
si_base_units(by=nil) click to toggle source

Returns an array representing the base SI units for the physical quantity described by self

If no argument is given, the array holds instances of Unit::Base (or subclasses) which represent each base unit. Alternatively only the names or symbols of each unit can be returned by providing the appropriate unit attribute as a symbolized argument, e.g.

Dimensions.energy.si_base_units       #=> [ #<Quantify::Unit: .. >,
                                            #<Quantify::Unit: .. >,
                                            ... ]

Dimensions.energy.si_base_units :name

                                      #=> [ "metre squared",
                                            "per second squared",
                                            "kilogram"]    #

Dimensions.force.units :symbol        #=> [ "m", "s^-2", "kg"]
# File lib/quantify/dimensions.rb, line 317
def si_base_units(by=nil)
  self.to_hash.map do |dimension,index|
    Unit.base_quantity_si_units.select do |unit|
      unit.measures == dimension.remove_underscores
    end.first.clone ** index
  end.map(&by).to_a
end
si_unit() click to toggle source

Returns the SI unit for the physical quantity described by self.

Plane/solid angle are special cases which are dimensionless units, and so are handled explicitly. Otherwise, the si base units for each of the base dimensions of self are indentified and the corresponding compound unit is derived. If this new unit is the same as a known (SI derived) unit, the known unit is returned.

Dimensions.energy.units                  #=> #<Quantify::Dimensions: .. >

Dimensions.energy.si_unit.name           #=> 'joule'

Dimensions.kinematic_viscosity.si_unit.name

                                         #=> 'metre squared per second'
# File lib/quantify/dimensions.rb, line 287
def si_unit
  return Unit.steridian if describe == 'solid angle'
  return Unit.radian if describe == 'plane angle' 
  return si_base_units.inject(Unit.unity) do |compound,unit|
    compound * unit
  end.or_equivalent
rescue
  return nil
end
times(other)
Alias for: multiply
units(by=nil) click to toggle source

Returns an array containing the known units which represent the physical quantity described by self

If no argument is given, the array holds instances of Unit::Base (or subclasses) which represent each unit. Alternatively only the names or symbols of each unit can be returned by providing the appropriate unit attribute as a symbolized argument, e.g.

Dimensions.energy.units             #=> [ #<Quantify::Dimensions: .. >,
                                          #<Quantify::Dimensions: .. >,
                                          ... ]

Dimensions.mass.units :name         #=> [ 'kilogram', 'ounce',
                                          'pound', ... ]

Dimensions.length.units :symbol     #=> [ 'm', 'ft', 'yd', ... ]
# File lib/quantify/dimensions.rb, line 267
def units(by=nil)
  Unit.units.select { |unit| unit.dimensions == self }.map(&by).to_a
end
unload() click to toggle source

Remove from system of known units.

# File lib/quantify/dimensions.rb, line 214
def unload
  Dimensions.unload(self.physical_quantity)
end

Protected Instance Methods

base_quantities() click to toggle source

Returns an array containing the names of the instance variables which represent the base quantities of self. This enables various operations to be performed on these variables without touching the @physical_quantity variable.

# File lib/quantify/dimensions.rb, line 455
def base_quantities
  quantities = self.instance_variables
  if RUBY_VERSION < "1.9"
    quantities.delete("@physical_quantity")
    return quantities.map(&:to_sym)
  else
    quantities.delete(:@physical_quantity)
    return quantities
  end
end
denominator_quantities() click to toggle source

Just the base quantities which have negative indices

# File lib/quantify/dimensions.rb, line 472
def denominator_quantities
  base_quantities.select { |quantity| self.instance_variable_get(quantity) < 0 }
end
enumerate_base_quantities(options) click to toggle source

Method for initializing the base quantities of self.

Where base quantities are already defined, the new indices are added to the existing ones. This represents the multiplication of base quantities (multiplication of similar quantities involves the addition of their powers).

This method is therefore used in the multiplication of Dimensions objects, but also in divisions and raising of powers following other operations.

# File lib/quantify/dimensions.rb, line 498
def enumerate_base_quantities(options)
  options.each_pair do |base_quantity,index|
    base_quantity = base_quantity.to_s.downcase.to_sym
    unless index.is_a?(Integer) && BASE_QUANTITIES.include?(base_quantity)
      raise Exceptions::InvalidDimensionError, "An invalid base quantity was specified (#{base_quantity})"
    end
    variable = "@#{base_quantity}"
    if self.instance_variable_defined?(variable)
      new_index = self.instance_variable_get(variable) + index
      if new_index == 0
        remove_instance_variable(variable)
      else
        self.instance_variable_set(variable, new_index)
      end
    else
      self.instance_variable_set(variable, index)
    end
  end
end
make_dimensionless() click to toggle source

Make object represent a dimensionless quantity.

# File lib/quantify/dimensions.rb, line 519
def make_dimensionless
  @physical_quantity = 'dimensionless'
  base_quantities.each { |var| remove_instance_variable(var) }
end
numerator_quantities() click to toggle source

Just the base quantities which have positive indices

# File lib/quantify/dimensions.rb, line 467
def numerator_quantities
  base_quantities.select { |quantity| self.instance_variable_get(quantity) > 0 }
end
to_hash() click to toggle source

Returns a hash representation of the base dimensions of self. This is used in various operations and is useful for instantiating new objects with the same base dimensions.

# File lib/quantify/dimensions.rb, line 480
def to_hash
  hash = {}
  base_quantities.each do |variable|
    hash[variable.to_s.gsub("@","").to_sym] = self.instance_variable_get(variable)
  end
  return hash
end