(*********************************************************************** This file was generated automatically by the Mathematica front end. It contains Initialization cells from a Notebook file, which typically will have the same name as this file except ending in ".nb" instead of ".m". This file is intended to be loaded into the Mathematica kernel using the package loading commands Get or Needs. Doing so is equivalent to using the Evaluate Initialiation Cells menu command in the front end. DO NOT EDIT THIS FILE. This entire file is regenerated automatically each time the parent Notebook file is saved in the Mathematica front end. Any changes you make to this file will be overwritten. ***********************************************************************) (* :Name: Miscellaneous`V3ExtendUnits` *) (* :Title: Extending Unit Conversions *) (* :Author: David J.M. Park Jr., 5605 West Falls Road, Mt. Airy, MD 21771\n mailto:djmp@earthlink.net *) (* :Summary: This package extends the standard Miscellaneous`Units` package by reaching inside root expressions, converting to approximate degrees, formatting numbers, adding a PrefixForm, and providing a consistent way to provide input for numeric functions. *) (* :Context: Miscellaneous`V3ExtendUnits` *) (* :Package Version: 1.01 *) (* :Copyright: Copyright 1999, David J.M. Park Jr. *) (* :Keywords: units, formatting, deunitizing *) (* :Mathematica Version: 3.0 *) (* :Warnings: The messages NumberForm::sigz and Convert::temp are turned Off by the package. *) (* :Discussion: This package extends the standard Mathematica package Miscellaneous`Units` and makes it easier to use. PowerExpand and ComplexExpand can be automatically applied or disabled. Internally it converts all units to base SI units which allows greater simplification. It allows specification of the output format for the number at the same time unit conversion is done. A new format PrefixForm is provided which uses the standard SI unit prefixes and automatically applies them. It corrects the degree conversion problem with approximate numbers. It will convert expressions which contain roots. It provides a consistent way to suppress units when using Plot and other numeric functions. Users may also define their own units. *) BeginPackage[ "Miscellaneous`V3ExtendUnits`",{"Miscellaneous`Units`", "Miscellaneous`SIUnits`"}] Miscellaneous`V3ExtendUnits::usage= "The Miscellaneous`ExtendUnits package is used for converting output to the \ desired units, precision and form. It can also be used to remove units from \ an expression in a controlled manner." AllowComplexExpand::usage= "AllowComplexExpand is a ToUnit option which specifies whether ToUnit is \ permitted to use ComplexExpand. The default value is True. The rule Sign[_]\ \[Rule] 1 is also used when this option is enabled. The option is also used \ in test evaluations in DeunitizeWithReference." AllowPowerExpand::usage= "AllowPowerExpand is a ToUnit option which specifies whether ToUnit is \ permitted to use PowerExpand. The default value is True. The option is also \ used in test evaluations in DeunitizeWithReference." BaseSI::usage= "BaseSI[expr] will convert all units in expr to base SI units with no \ derived SI units." NewUnitRules::usage= "NewUnitRules is a set of rules which will convert newly installed units to \ base SI units."; Deunitize::usage= "Deunitize[expr, varlist:{}, system:SI] will convert the expr to the system \ (SI,MKS,CGS)of units specified and then remove all units so the expression \ can be used in numerical routines. varlist gives a list of symbol variables \ in the expression which are to be preserved." DeunitizeWithReference::usage= "DeunitizeWithReference[f[args], vars, outunit, opts...] will Deunitize \ f[args], using the supplied arguments. vars is the list of the variables for \ the function. outunit specifies the desired output unit. The option \ ReferenceValues may be used to give safe values for evaluating f which is \ done to check that the units are consistent. The default numerical values are \ {1, 1,...}. AllowPowerExpand and AllowComplexExpand can also be used to guide \ the test evaluation. Unless PrintReferenceEquation is set to False, a \ reference equation will be printed using BaseSI units everywhere except for \ the input variables and output unit." DeunitizeWithReference::units="Bad unit specification."; \!\(\(InstallNewUnit::usage = \*"\"\\""; \)\) NewUnitRules::usage= "NewUnitRules is the list of new unit equivalences which have been \ installed during the current session."; ParsePrecision::usage= "ParsePrecision is an option of ToUnit used when parsing a quantity to a \ series of descending compatible units. It controls when a remainder is \ rounded up to the next integer unit and when a final quantity is dropped." ParseUnits::usage= "ParseUnits is a wrapper for a set of descending compatible units which \ cause ToUnit to break the quantity into the set of units. Example: \ ToUnit[ParseUnits[Hour, Minute, Second]][1.33 Day] \[Rule] \!\( \*TagBox[\(31\ Hour + 55\ Minute + 12. \ Second\), HoldForm]\)"; PrefixForm::usage= "PrefixForm[number, precision:6, offset:1] is a new number formatting \ routine which uses unit prefixes, selecting the proper one. The returned unit \ expression is wrapped in HoldForm so that the prefix will always come before \ the units. If the number is outside the Atto-Exa range a normal number is \ returned. The offset is used to control the breaking between adjacent \ prefixes. 0 will give values xxx.unit to x.xx unit; 1 gives xx.x unit to \ 0.xxx unit,etc. The default offset is 1." PrintDegreeSymbol::usage= "If the ToUnit option PrintDegreeSymbol is True, Degree is printed as \"\ \[Degree]\" inclosed in quotes. If False,Degree is wrapped in HoldForm." PrintReferenceEquation::usage= "An option for DeunitizeWithReference which tells whether to print the \ reference equation showing in detail how units enter into the expression. The \ default is True." ReferenceValues::usage= "An option for DeunitizeWithReference which sets a list of argument values \ for a test evaluation of the function being deunitized. The default uses \ values of 1 for all arguments. These may be improper for some functions." ReleaseDegree::usage= "ReleaseDegree[expr] will convert the output forms produced in Degree \ conversions back to a usable radian input form." TemperatureScale::usage= "TemperatureScale is an option of ToUnit which specifies temperature scale \ conversion using ConvertTemperature. The default is TemperatureScale \[Rule] \ False." ToCelsius::usage="ToCelsius[t_] converts a temperature to the Celsius scale." ToFahrenheit::usage= "ToFahrenheit[t_] converts a temperature to the Fahrenheit scale." ToKelvin::usage="ToKelvin[t_] converts a temperature to the Kelvin scale." ToRankine::usage="ToRankine[t_] converts a temperature to the Rankine scale." ToUnit::usage= "ToUnit[unit,options...] is a pure function which sets the units, precision \ and form for an expression and returns the new expression. A usage example is \ 1 Yard // ToUnit[Inch] --> 36. Inch. ToUnit[unit,n,options...] is applied to \ the n'th element of a list. ToUnit[unit,list,options...] applies ToUnit to \ all the level 1 items enumerated in the list. If unit is a list of compatible \ units, a list of conversions is returned. If unit is parse[unit1,unit2,...] \ the expression is parsed out in supposedly descending units." ToUnit::uniterr="Can't convert from `1` to `2`."; ToUnitForms::usage= "ToUnitForms[unit,{form...},options...] converts any expression of the form \ x_form to ToUnit[unit][x]form where form is one of the items on the list of \ forms." ToUnitList::usage= "ToUnitList[unit,options...] converts an entire list to the same unit." ToUnitRule::usage= "ToUnitRule[unit,options...] applies ToUnit to the second element in a \ rule. ToUnitRule[unit,n,options...] applies ToUnit to the n'th rule in a list \ of rules. ToUnitRule[unit,list,options...] applies ToUnit to all the level 1 \ rules enumerated in the list." ToUnitVectorRule::usage= "ToUnitVectorRule[unit,options...] converts a Rule in which the right hand \ side is a Vector in list form. ToUnitVectorRule[unit,n,options...] applies \ ToUnitVectorRule to the n'th element of a list." UnitForm::usage= "UnitForm is an option of ToUnit which specifies the output form in ToUnit. \ Choices are (Automatic \[Or] a pure function). The default is Automatic which \ just gives the standard Mathematica output. The pure function might take the \ form: (NumberForm[#, 3]&) or (PrefixForm[#, 5]&) or other Mathematica number \ formatting functions." UnitPosition::usage= "UnitPosition is an option of ToUnit which specifies the location in the \ expression to apply the specifications. It must be a position list. The \ default is Automatic, the whole expression." \!\(Options[ToUnit] = {UnitForm \[Rule] Automatic, UnitPosition \[Rule] Automatic, TemperatureScale \[Rule] False, AllowPowerExpand \[Rule] True, AllowComplexExpand \[Rule] False, PrintDegreeSymbol \[Rule] False, ParsePrecision \[Rule] 10\^\(-13\)}\) Options[DeunitizeWithReference]={AllowComplexExpand\[Rule]False, AllowPowerExpand\[Rule]True,PrintReferenceEquation\[Rule]True, ReferenceValues\[Rule]Automatic}; Begin["`Private`"] Off[NumberForm::sigz] Off[Convert::temp] fakedegree=Unique[]; NewUnitRules={}; InstallNewUnit[rule_Rule]:= Module[{}, AppendTo[NewUnitRules,BaseSI[N[rule]]]; Evaluate[rule\[LeftDoubleBracket]1\[RightDoubleBracket]]::usage= ToString[rule\[LeftDoubleBracket]1\[RightDoubleBracket]]<> " is an installed unit.";] \!\(\(\(PrefixForm[x_, prec_: 6, \ offset_: 1] := \n\t Module[{man, exp, num, ord, ans, prelist = {Atto, Femto, Pico, Nano, Micro, Milli, zero, Kilo, Mega, Giga, Tera, Peta, Exa}}, \n\t\tIf[NumberQ[x], Return[x]]; \n\t\t num\ = \ SetPrecision[First[x], prec + 1]; \n \t\t{man, exp} = MantissaExponent[num]; \n\t\t If[man \[GreaterEqual] 1.0, \(++exp\)]; \n\t\t\(--exp\); \ (*\ Decrement\ to\ put\ one\ digit\ to\ left\ of\ point\ *) \n\t\ \ ord\ = \ Floor[\(exp + offset\)\/3] + 7; \n\t\t If[ord < 1 \[Or] ord > 13 \[Or] ord \[Equal] 7, ord = 0]; \n\t\t N[If[ord \[NotEqual] 0, \n\t\t\t\ \ \ \ \ ans\ = \ HoldForm[Evaluate[\(num\/10\^\((3 \((ord - 7)\))\)\) Rest[x]]]; \n \t\t\t\ \ \ \ \ ans\ = \ Insert[ans, prelist\[LeftDoubleBracket]ord\[RightDoubleBracket], {1, 2}], x], prec]\ ]; \)\n\)\) myConvert[inexpr_,outunits_]:= Module[{outBaseSI,fac,answer,outbase,outextra}, outbase= outunits/.{Gross\[Rule]1,Dozen\[Rule]1,BakersDozen\[Rule]1, Percent\[Rule]1}; outextra=outunits/outbase; outBaseSI=PowerExpand[BaseSI[outbase]]outextra; fac=If[Length[1.0outBaseSI]>1,First[1.0outBaseSI],1.0outBaseSI]; answer=Convert[inexpr,outBaseSI]/fac; If[Length[answer]>1,First[answer]outunits,answer] ] \!\(ToUnit[ unit_ /; \[Not] VectorQ[unit] \[And] \[Not] \((Head[unit] === ParseUnits)\), opts___Rule] := \n\t\ Module[{prec, accur, form, loc, tscale, preoffset, allowcomplex, allowpower, subexpr, fullexpr, degexp, degunit, oldunit, printdegree, degBaseSI}, \n\t\t\n \t\t (*\ Extract\ the\ options\ *) \n\t\t form = \(UnitForm\ \ \ \ \ \ \ \ \ \ \ \ \ /. {opts}\) /. Options[ToUnit]; \n\t\t loc = \(UnitPosition\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ /. {opts}\) /. Options[ToUnit]; \n\t\t tscale = \(TemperatureScale\ \ \ \ /. {opts}\) /. Options[ToUnit]; \n \t\tallowcomplex = \(AllowComplexExpand\ /. {opts}\) /. Options[ToUnit]; \n\t\ \ allowpower = \(AllowPowerExpand\ /. {opts}\) /. Options[ToUnit]; \n \t\tprintdegree = \(PrintDegreeSymbol /. {opts}\) /. Options[ToUnit]; \n\t\t\n\t\t\n \t\t (*\ Pick\ out\ the\ subexpression\ if\ necessary\ *) \n\t\ \ \ Which[loc === Automatic, \ subexpr = 1.0 #, \n \t\t\t\ \ \ \ \ \ \ \ \ \ \ \ True, subexpr\ = 1.0\ Part[#, Sequence@@loc]; \n \t\t\t\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ fullexpr = #]; \n\t\t\n\t\t (*\ Remove\ Print\ Wrappers\ *) \n \t\ \ \ subexpr = subexpr /. {NumberForm[x_, ___] \[Rule] x, ScientificForm[x_, ___] \[Rule] x, EngineeringForm[x_, ___] \[Rule] x, "\<\[Degree]\>" \[Rule] Degree}; \n\t\t\n \t\t (*\ Fix\ up\ Degree\ Problem\ and\ make\ E\ and\ \[Pi]\ numerical \ *) \n\t\ \ \ degexp = Exponent[unit, Degree]; \n\t\t\n\t\t\ subexpr\ = \ \(\((\(180\/\[Pi]\) fakedegree)\)\^degexp\) subexpr; \n \t\ \ \ degunit = unit /. Degree \[Rule] fakedegree; \n\t\t subexpr = subexpr /. {\[Pi] \[Rule] N[\[Pi]], E \[Rule] N[E]}; \n\t\t \n\t\t (*\ Do\ the\ Unit\ conversion\ on\ the\ \(subexpression . \)\ *) \n \t\ \ \ Which[\n\t\t\tsubexpr === 0, subexpr = 0. degunit, \n\t\t\t True, \n\t\t\t\ \ \ subexpr\ = \ ReleaseHold[subexpr]; \n \t\t\t\ \ \ \n\t\t\t\ \ \ If[tscale \[Equal] False, \n \t\t\t\t\ \ \ \ \ \ (*\ Regular\ Conversion\ *) \n\t\t\t\ \ \ subexpr = N[BaseSI[subexpr]]; \n\t\t\t\ \ \ If[allowcomplex, \n\t\t\t\t\ \ \ \ subexpr = ComplexExpand[subexpr] /. Sign[_] \[Rule] 1]; \n \t\t\t\t\ If[allowpower, subexpr = subexpr //. Power[a_, b_] \[RuleDelayed] Power[Expand[a], b]; subexpr = PowerExpand[subexpr]]; \n \t\t\t\t (*\ Convert\ with\ allowance\ for\ installed\ units\ *) \n\t\t\t\tsubexpr = myConvert[subexpr, degunit], \n \t\t\t\t\ \ \ \ \ \ \ \n \t\t\t\t (*\ Temperature\ Scale\ Conversion\ *) \n \t\t\t\ \ \ \ \ \ \ \ \ \ oldunit\ = \ Rest[subexpr]; \n \t\t\t\t\ \ \ \ \ \ \ \ subexpr\ = ConvertTemperature[First[subexpr], oldunit, unit] unit]\n \t\t\t\ ]; \n\t\t\n \t\t (*\ Apply\ the\ specified\ number\ \(format . \)\ *) \n\t\t subexpr\ = Which[\n\t\t\tform === Automatic, subexpr, \n\t\t\tTrue, form[subexpr]]; \n\t\t\n\t\t If[printdegree, subexpr = subexpr /. fakedegree \[Rule] "\<\[Degree]\>", subexpr = subexpr /. fakedegree \[Rule] HoldForm[\[Degree]]]; \n \t\t (*\ Replace\ the\ subexpression\ if\ necessary\ *) \n\t\ \ \ Which[loc === Automatic, fullexpr\ = \ subexpr, \n \t\t\t\ \ \ \ \ \ \ \ \ \ \ \ True, fullexpr\ = \ ReplacePart[fullexpr, subexpr, loc]]\n\t\t]&\) ToUnit[unit_/;\[Not]VectorQ[unit],n_Integer,opts___Rule]:= MapAt[ToUnit[unit,opts],#,n]& ToUnit[unit_/;\[Not]VectorQ[unit],items:{__Integer},opts___Rule]:= MapAt[ToUnit[unit,opts],#,Partition[items,1]]& ToUnit[units_List,opts___Rule]:= Table[ToUnit[units\[LeftDoubleBracket]i\[RightDoubleBracket],opts][#],{i,1, Length[units]}]& ToUnit[units_List,n_Integer,opts___Rule]:= ReplacePart[#, Table[ToUnit[units\[LeftDoubleBracket]i\[RightDoubleBracket],opts][# \[LeftDoubleBracket]n\[RightDoubleBracket]],{i,1,Length[units]}], n]& ToUnit[units_List,items:{__Integer},opts___Rule]:= MapAt[ToUnit[units,opts],#,Partition[items,1]]& ToUnitRule[unit_/;\[Not]VectorQ[unit]\[And]\[Not](Head[unit]===ParseUnits), opts___Rule]:=ToUnit[unit,opts,UnitPosition\[Rule]{2}] ToUnitRule[unit_/;\[Not]VectorQ[unit]\[And]\[Not](Head[unit]===ParseUnits), n_Integer,opts___Rule]:=ToUnit[unit,opts,UnitPosition\[Rule]{n,2}] ToUnitRule[unit_/;\[Not]VectorQ[unit]\[And]\[Not](Head[unit]===ParseUnits), items:{__Integer},opts___Rule]:= MapAt[ToUnit[unit,opts,UnitPosition\[Rule]{2}],#,Partition[items,1]]& ToUnitRule[units_List,opts___Rule]:= ReplacePart[#, Table[ToUnit[units\[LeftDoubleBracket]i\[RightDoubleBracket],opts][# \[LeftDoubleBracket]2\[RightDoubleBracket]],{i,1,Length[units]}],{ 2}]& ToUnitRule[units_List,n_Integer,opts___Rule]:= ReplacePart[#, Table[ToUnit[units\[LeftDoubleBracket]i\[RightDoubleBracket],opts][# \[LeftDoubleBracket]n,2\[RightDoubleBracket]],{i,1, Length[units]}],{n,2}]& ToUnitRule[units_List,items:{__Integer},opts___Rule]:= Fold[ToUnitRule[units,#2,opts][#1]&,#1,items]& ToUnitRule[units_/;Head[units]===ParseUnits,opts___Rule]:= ReplacePart[#, ToUnit[units,opts][#\[LeftDoubleBracket]2\[RightDoubleBracket]],{2}]& ToUnitRule[units_/;Head[units]===ParseUnits,n_Integer,opts___Rule]:= ReplacePart[#, ToUnit[units,opts][#\[LeftDoubleBracket]n,2\[RightDoubleBracket]],{n, 2}]& ToUnitRule[units_/;Head[units]===ParseUnits,items:{__Integer},opts___Rule]:= Fold[ToUnitRule[units,#2,opts][#1]&,#1,items]& ToUnitList[units_,opts___Rule]:=Map[ToUnit[units,opts],#]& \!\(ToUnit[units_ /; Head[units] === ParseUnits, opts___Rule] := \n\t Module[{len = Length[units], result = {}, i, x, xf, xr, y, expr, sgn, parseprecision}, \n\t\t parseprecision = \(ParsePrecision /. {opts}\) /. Options[ToUnit]; \n \t\texpr = \(ToUnit[units\[LeftDoubleBracket]1\[RightDoubleBracket], UnitForm \[Rule] Automatic]\)[1.0 #]; \n\t\t sgn = If[NumericQ[expr], Sign[expr], Sign[First[expr]]]; \n\t\t If[sgn \[Equal] \(-1\), expr = \(-expr\)]; \n\t\t For[i = 1, i < len, \(i++\), \n\t\t\t x = expr // ToUnit[units\[LeftDoubleBracket]i\[RightDoubleBracket], UnitForm \[Rule] Automatic, opts]; \n \t\t\t{xf, xr} = If[NumericQ[x], {x, 1}, {First[x], Rest[x]}]; \n \t\t\ty = IntegerPart[xf]; \n\t\t\t If[Abs[1 - FractionalPart[xf]] < parseprecision, \(++y\); expr = 0. xr, expr = FractionalPart[xf]\ xr\ ]; \n\t\t\t If[\[Not] \((y \[Equal] 0)\), AppendTo[result, y\ xr]]]; \n\t\t\n \t\tx = expr // ToUnit[units\[LeftDoubleBracket]len\[RightDoubleBracket], UnitForm \[Rule] Automatic, opts]; \n\t\t If[x\/units\[LeftDoubleBracket]len\[RightDoubleBracket] > parseprecision, AppendTo[result, x]]; \n\t\tresult = sgn\ result; \n\t\tWhich[Length[result] > 1, HoldForm[Evaluate[result]] /. List \[Rule] Plus, \n\t\t\t Length[result] \[Equal] 1, result\[LeftDoubleBracket]1\[RightDoubleBracket], \n\t\t\tTrue, 0. units\[LeftDoubleBracket]len\[RightDoubleBracket]]\n\t\t]&\) ToUnitVectorRule[unit_,opts___Rule]:= (#\[LeftDoubleBracket]1 \[RightDoubleBracket]\[Rule]ToUnitList[unit,opts][# \[LeftDoubleBracket]2\[RightDoubleBracket]])& ToUnitVectorRule[unit_,n_Integer,opts___Rule]:= Module[{temp}, temp=#\[LeftDoubleBracket]n,1 \[RightDoubleBracket]\[Rule]ToUnitList[unit,opts][# \[LeftDoubleBracket]n,2\[RightDoubleBracket]]; ReplacePart[#,temp,n] ]& ToUnitForms[unit_,forms_List,opts___Rule]:= Module[{expr,f}, expr=#; Do[expr= expr/.x_ forms\[LeftDoubleBracket]i \[RightDoubleBracket]\[RuleDelayed]ToUnit[unit,opts][x]forms \[LeftDoubleBracket]i\[RightDoubleBracket],{i,1, Length[forms]}]; expr]& \!\(BaseSI[expr_] := SI[expr /. NewUnitRules] /. {Hertz \[Rule] Second\^\(-1\), \n\t\t\t\t\t\t Newton \[Rule] Meter\ Kilogram\ Second\^\(-2\), \n\t\t\t\t\t\t Pascal \[Rule] \(Meter\^\(-1\)\) Kilogram\ Second\^\(-2\), \n \t\t\t\t\t\t Joule \[Rule] \(Meter\^2\) Kilogram\ System`Second\^\(-2\), \n \t\t\t\t\t\tWatt \[Rule] \(Meter\^2\) Kilogram\ Second\^\(-3\), \n \t\t\t\t\ \ \tCoulomb \[Rule] Ampere\ Second, \n\t\t\t\t\t\t Volt \[Rule] \(Meter\^2\) Kilogram\ \(Second\^\(-3\)\) Ampere\^\(-1\), \n \t\t\t\t\t\t Ohm \[Rule] \(Meter\^2\) Kilogram\ \(Second\^\(-3\)\) Ampere\^\(-2\), \n\t\t\t\t\t\t Siemens \[Rule] \(Meter\^\(-2\)\) \(Kilogram\^\(-1\)\) \(Second\^3\) Ampere\^2, \n \t\t\t\t\t\t Farad \[Rule] \(Meter\^\(-2\)\) \(Kilogram\^\(-1\)\) \(Second\^4\) Ampere\^2, \n \t\t\t\t\t\t Tesla \[Rule] Kilogram\ \(Second\^\(-2\)\) Ampere\^\(-1\), \n \t\t\t\t\t\t Weber \[Rule] \(Meter\^2\) Kilogram\ \(Second\^\(-2\)\) Ampere\^\(-1\), \n \t\t\t\t\t\t Henry \[Rule] \(Meter\^2\) Kilogram\ \(Second\^\(-2\)\) Ampere\^\(-2\), \n \t\t\t\ \ \ \ \ \ Amp \[Rule] Ampere, \n\t\t\t\ \ \ \ \ \ Lumen \[Rule] Candela, \n\t\ \ \ \ \ \ \t\ \ Lux \[Rule] Candela\ Meter\^\(-2\), \n\t\t\t\ \ \ \ \ \ Becquerel \[Rule] Second\^\(-1\), \n\t\ \ \ \ \ \ \ \ \t Gray \[Rule] \(Meter\^2\) Second\^\(-2\)}\) Deunitize[expr_,var_List:{},system_:SI]:= Module[{temp,locs}, temp=system[expr/.NewUnitRules]; locs=Position[temp,x_Symbol/;Count[var,x]\[Equal]0\[And]\[Not]NumericQ[x], Heads\[Rule]False]; If[locs=!={{}},ReplacePart[temp,1,locs],temp]] Attributes[DeunitizeWithReference]=HoldFirst; DeunitizeWithReference[f_[args__],vars_List,outunit_,opts___?OptionQ]:= Module[{heldargs,argsout,symargs,a,normalout,reffunc,numfunc,allowpower, allowcomplex,print,vals}, (* Extract the options *) allowcomplex=AllowComplexExpand/.{opts}/.Options[DeunitizeWithReference]; allowpower=AllowPowerExpand/.{opts}/.Options[DeunitizeWithReference]; print=PrintReferenceEquation/.{opts}/.Options[DeunitizeWithReference]; vals=ReferenceValues/.{opts}/.Options[DeunitizeWithReference]; (* Set arguments to values for a test evaluation to check units *) If[vals===Automatic,vals=Table[1,{Length[vars]}]]; argsout= List[args]/.x_Symbol \[RuleDelayed]vals \[LeftDoubleBracket]Sequence@@ Position[vars,x]\[RightDoubleBracket]/; Count[vars,x]\[NotEqual]0//Flatten; (* Check if output unit is consistent with the expression *) normalout=BaseSI[f@@argsout]//N; normalout= If[allowcomplex,ComplexExpand[normalout]/.Sign[_]\[Rule]1,normalout]; normalout = If[allowpower, normalout=normalout//.Power[a_,b_]\[RuleDelayed]Power[Expand[a],b]; PowerExpand[normalout],normalout]; normalout=If[NumericQ[normalout],1,Rest[1.0 normalout]]; heldargs=(HoldForm/@{args}); heldargs= heldargs/.HoldForm[x_]\[RuleDelayed]x/; And@@MapThread[FreeQ[x,#]&,{vars}]; heldargs=If[Head[#]=!=HoldForm,#/.x_\[RuleDelayed]BaseSI[x],#]&/@heldargs; symargs=Array[a,Length[heldargs]]; reffunc=(BaseSI[f[Sequence@@symargs]]/.(symargs\[Rule]heldargs//Thread))* normalout/HoldForm[Global`output HoldForm[outunit]]//Simplify; If[print,Print[reffunc]]; If[\[Not](NumberQ[BaseSI[normalout/outunit]]), Message[DeunitizeWithReference::units];Return[$Failed]]; Deunitize[reffunc/.Global`output\[Rule]1//ReleaseHold//ReleaseHold,vars, SI]] \!\(Attributes[ToKelvin] = {Listable}; \n ToKelvin[t_] := \n\t Module[{val = First[t], unit = Last[t]}, \n\t Which[\n\t\tunit === Kelvin, t, \n\t\tunit === \ Celsius, \((val + 273.15)\) Miscellaneous`SIUnits`Kelvin, \n\t\t unit === \ Fahrenheit, \((\(5\/9\) \((val - 32)\) + 273.15)\) Miscellaneous`SIUnits`Kelvin \ , \n\t\t\ unit === Rankine, \((val/1.8)\) Miscellaneous`SIUnits`Kelvin\ , \n\t\tTrue, t]]\) \!\(Attributes[ToCelsius] = {Listable}; \n ToCelsius[t_] := \n\t Module[{val = First[t], unit = Last[t]}, \n\t Which[\n\t\tunit === Celsius, t, \n\t\tunit === \ Kelvin, \((val - 273.15)\) Miscellaneous`Units`Celsius, \n\t\t unit === \ Fahrenheit, \((\(5\/9\) \((val - 32. )\))\) Miscellaneous`Units`Celsius, \n\t\t\t unit === Rankine, \((5/9 val - 273.15)\) Miscellaneous`Units`Celsius, \n\t\tTrue, t]]\) \!\(Attributes[ToFahrenheit] = {Listable}; \n ToFahrenheit[t_] := \n\t Module[{val = First[t], unit = Last[t]}, \n\t Which[\n\t\tunit === Fahrenheit, t, \n\t\tunit === \ Kelvin, \((\(9\/5\) \((val - 273.15)\) + 32)\) Miscellaneous`Units`Fahrenheit, \n\t\tunit === \ Celsius, \((\(9\/5\) val + 32. )\) Miscellaneous`Units`Fahrenheit, \n\t\t\t unit === Rankine, \((val - 459.67)\) Miscellaneous`Units`Fahrenheit, \n\t\tTrue, t]]\) Attributes[ToRankine]={Listable}; ToRankine[t_]:= Module[{val=First[t],unit=Last[t]}, Which[ unit===Rankine,t, unit=== Kelvin,(1.8 val)Miscellaneous`Units`Rankine, unit=== Celsius,((val+273.15)9/5)Miscellaneous`Units`Rankine, unit===Fahrenheit,(val+459.67)Miscellaneous`Units`Rankine, True,t]] ReleaseDegree[x_]:=x/.{"\[Degree]"\[Rule]Degree,HoldForm[Degree]\[Rule]Degree} End[] Protect[Evaluate[Context[]<>"*"]]; Unprotect[NewUnitRules]; EndPackage[]