4

To my propose I would like to extend the elements package to print too the melting and boiling points of chemical elements. Using the same logic used in elements package, I thought about creating commands like those:

% default: unit=kelvin    
\DeclareAtomMeltingPoint[unit=kelvin|celsius|fahrenheit]{<atomic number>}{<temperature>}

to call one of these commands:

% Used before begin document or in packages/classes    
\DeclareAtomMeltingPointKelvin{<atomic number}{<temperature in kelvin>}
\DeclareAtomMeltingPointCelsius{<atomic number}{<temperature in celsius>}
\DeclareAtomMeltingPointFahrenheit{<atomic number}{<temperature in fahrenheit>}

To prints the temperatures inside document, I would use commands like this:

% Used inside document
\meltingpoint[<unit=kelvin|celsius|fahrenheit>]{<atomic number>|<element symbol>|<element name>}

How can I implements this?

  • 2
    I wonder why the downvote ¯\_(ツ)_/¯. This is a perfectly valid question. – Phelype Oleinik Apr 20 at 3:56
4

I'd not use unit=, because this hinders expandability.

I take the approach of using a property list.

\documentclass{article}
\usepackage{xparse,siunitx}

\DeclareSIUnit{\fahrenheit}{\degree F}

\ExplSyntaxOn
\NewDocumentCommand{\DeclareAtomMeltingPoint}{O{kelvin}mm}
 {
  \group_begin:
  \keys_set:nn { grs/meltingpoint } { #1 }
  \prop_gput:Nnx \g_grs_meltingpoint_prop { #2 }
   {
    \__grs_meltingpoint_store:n { #3 }
   }
  \group_end:
 }

\prop_new:N \g_grs_meltingpoint_prop

\keys_define:nn { grs/meltingpoint }
 {
  kelvin     .code:n = \cs_set_eq:NN \__grs_meltingpoint_store:n \__grs_meltingpoint_in_kelvin:n,
  K          .code:n = \cs_set_eq:NN \__grs_meltingpoint_store:n \__grs_meltingpoint_in_kelvin:n,
  celsius    .code:n = \cs_set_eq:NN \__grs_meltingpoint_store:n \__grs_meltingpoint_in_celsius:n,
  C          .code:n = \cs_set_eq:NN \__grs_meltingpoint_store:n \__grs_meltingpoint_in_celsius:n,
  fahrenheit .code:n = \cs_set_eq:NN \__grs_meltingpoint_store:n \__grs_meltingpoint_in_fahrenheit:n,
  F          .code:n = \cs_set_eq:NN \__grs_meltingpoint_store:n \__grs_meltingpoint_i_fahrenheit:n,
 }

\cs_new:Nn \__grs_meltingpoint_in_kelvin:n
 {
  \fp_eval:n { #1 }
 }
\cs_new:Nn \__grs_meltingpoint_in_celsius:n
 {
  \fp_eval:n { #1 + 273.15 }
 }
\cs_new:Nn \__grs_meltingpoint_in_fahrenheit:n
 {
  \fp_eval:n { (#1 + 459.67)*5/9 }
 }

\NewExpandableDocumentCommand{\meltingpoint}{sO{kelvin}m}
 {
  \IfBooleanTF{#1}
   { % we want the unit
    \str_case:nn { #2 }
     {
      {kelvin}{\SI{\__grs_meltingpoint_out_kelvin:n{#3}}{\kelvin}}
      {K}{\SI{\__grs_meltingpoint_out_kelvin:n{#3}}{\kelvin}}
      {celsius}{\SI{\__grs_meltingpoint_out_celsius:n{#3}}{\celsius}}
      {C}{\SI{\__grs_meltingpoint_out_celsius:n{#3}}{\celsius}}
      {fahrenheit}{\SI{\__grs_meltingpoint_out_fahrenheit:n{#3}}{\fahrenheit}}
      {F}{\SI{\__grs_meltingpoint_out_fahrenheit:n{#3}}{\fahrenheit}}
     }
   }
   { % no unit
    \str_case:nn { #2 }
     {
      {kelvin}{\__grs_meltingpoint_out_kelvin:n{#3}}
      {K}{\__grs_meltingpoint_out_kelvin:n{#3}}
      {celsius}{\__grs_meltingpoint_out_celsius:n{#3}}
      {C}{\__grs_meltingpoint_out_celsius:n{#3}}
      {fahrenheit}{\__grs_meltingpoint_out_fahrenheit:n{#3}}
      {F}{\__grs_meltingpoint_out_fahrenheit:n{#3}}
     }
   }
 }

\cs_new:Nn \__grs_meltingpoint_out_kelvin:n
 {
  \prop_item:Nn \g_grs_meltingpoint_prop { #1 }
 }
\cs_new:Nn \__grs_meltingpoint_out_celsius:n
 {
  \fp_eval:n { \prop_item:Nn \g_grs_meltingpoint_prop { #1 } - 273.15 }
 }
\cs_new:Nn \__grs_meltingpoint_out_fahrenheit:n
 {
  \fp_eval:n { \prop_item:Nn \g_grs_meltingpoint_prop { #1 } * 9/5 - 459.67 }
 }

\ExplSyntaxOff

\DeclareAtomMeltingPoint[celsius]{79}{1064}

\begin{document}

\meltingpoint*[kelvin]{79}
\meltingpoint[kelvin]{79}
\meltingpoint*[K]{79}
\meltingpoint[K]{79}

\meltingpoint*[celsius]{79}
\meltingpoint[celsius]{79}
\meltingpoint*[C]{79}
\meltingpoint[C]{79}

\meltingpoint*[fahrenheit]{79}
\meltingpoint[fahrenheit]{79}
\meltingpoint*[F]{79}
\meltingpoint[F]{79}

\end{document}

You can use either the long name or the initial, for ease of input. The *-version uses \SI to typeset the value with the required unit.

The declaration can use any unit, the value is stored in kelvin.

enter image description here

A slightly different version with support also for boiling points and avoiding code duplication.

\documentclass{article}
\usepackage{xparse,siunitx}

\DeclareSIUnit{\fahrenheit}{\degree F}

\ExplSyntaxOn
\NewDocumentCommand{\DeclareAtomMeltingPoint}{O{kelvin}mm}
 {
  \prop_gput:Nnx \g_grs_meltingpoint_prop { #2 }
   {
    \use:c { __grs_temperature_in_#1:n } { #3 }
   }
 }
\NewDocumentCommand{\DeclareAtomBoilingPoint}{O{kelvin}mm}
 {
  \prop_gput:Nnx \g_grs_boilingpoint_prop { #2 }
   {
    \use:c { __grs_temperature_in_#1:n } { #3 }
   }
 }

\NewExpandableDocumentCommand{\meltingpoint}{sO{kelvin}m}
 {
  \IfBooleanTF{#1}
   { % we want the unit
    \grs_point_si:Nnn \g_grs_meltingpoint_prop { #2 } { #3 }
   }
   {
    \grs_point:Nnn \g_grs_meltingpoint_prop { #2 } { #3 }
   }
 }
\NewExpandableDocumentCommand{\boilingpoint}{sO{kelvin}m}
 {
  \IfBooleanTF{#1}
   { % we want the unit
    \grs_point_si:Nnn \g_grs_boilingpoint_prop { #2 } { #3 }
   }
   {
    \grs_point:Nnn \g_grs_boilingpoint_prop { #2 } { #3 }
   }
 }

\prop_new:N \g_grs_meltingpoint_prop
\prop_new:N \g_grs_boilingpoint_prop

\cs_new:Nn \__grs_temperature_in_kelvin:n
 {
  \fp_eval:n { #1 }
 }
\cs_set_eq:NN \__grs_temperature_in_K:n \__grs_temperature_in_kelvin:n

\cs_new:Nn \__grs_temperature_in_celsius:n
 {
  \fp_eval:n { #1 + 273.15 }
 }
\cs_set_eq:NN \__grs_temperature_in_C:n \__grs_temperature_in_celsius:n

\cs_new:Nn \__grs_temperature_in_fahrenheit:n
 {
  \fp_eval:n { (#1 + 459.67)*5/9 }
 }
\cs_set_eq:NN \__grs_temperature_in_F:n \__grs_temperature_in_fahrenheit:n

\cs_new:Nn \__grs_temperature_out_kelvin:Nn
 {
  \prop_item:Nn #1 { #2 }
 }
\cs_new:Nn \__grs_temperature_out_celsius:Nn
 {
  \fp_eval:n { (\prop_item:Nn #1 { #2 }) - 273.15 }
 }
\cs_new:Nn \__grs_temperature_out_fahrenheit:Nn
 {
  \fp_eval:n { (\prop_item:Nn #1 { #2 }) * 9/5 - 459.67 }
 }

\cs_new:Nn \grs_point_si:Nnn
 {
  \str_case:nn { #2 }
   {
    {kelvin}{\__grs_point_si:NNnn #1 \__grs_temperature_out_kelvin:Nn {#3} {\kelvin}}
    {K}{\__grs_point_si:NNnn #1 \__grs_temperature_out_kelvin:Nn {#3} {\kelvin}}
    {celsius}{\__grs_point_si:NNnn #1 \__grs_temperature_out_celsius:Nn {#3} {\celsius}}
    {C}{\__grs_point_si:NNnn #1 \__grs_temperature_out_celsius:Nn {#3} {\celsius}}
    {fahrenheit}{\__grs_point_si:NNnn #1 \__grs_temperature_out_fahrenheit:Nn {#3} {\fahrenheit}}
    {F}{\__grs_point_si:NNnn #1 \__grs_temperature_out_fahrenheit:Nn {#3} {\fahrenheit}}
   }
 }
\cs_new:Nn \grs_point:Nnn
 {
  \str_case:nn { #2 }
   {
    {kelvin}{\__grs_point:NNn #1 \__grs_temperature_out_kelvin:Nn {#3}}
    {K}{\__grs_point:NNn #1 \__grs_temperature_out_kelvin:Nn {#3}}
    {celsius}{\__grs_point:NNn #1 \__grs_temperature_out_celsius:Nn {#3}}
    {C}{\__grs_point:NNn #1 \__grs_temperature_out_celsius:Nn {#3}}
    {fahrenheit}{\__grs_point:NNn #1 \__grs_temperature_out_fahrenheit:Nn {#3} }
    {F}{\__grs_point:NNn #1 \__grs_temperature_out_fahrenheit:Nn {#3} }
   }
 }

\cs_new_protected:Nn \__grs_point_si:NNnn
 {
  \SI{#2 #1 {#3}}{#4}
 }
\cs_new:Nn \__grs_point:NNn
 {
  #2 #1 {#3}
 }

\ExplSyntaxOff

\DeclareAtomMeltingPoint[celsius]{79}{1064}
\DeclareAtomBoilingPoint[celsius]{1}{-252.9}

\begin{document}

\meltingpoint*[kelvin]{79}
\meltingpoint[kelvin]{79}
\meltingpoint*[K]{79}
\meltingpoint[K]{79}

\meltingpoint*[celsius]{79}
\meltingpoint[celsius]{79}
\meltingpoint*[C]{79}
\meltingpoint[C]{79}

\meltingpoint*[fahrenheit]{79}
\meltingpoint[fahrenheit]{79}
\meltingpoint*[F]{79}
\meltingpoint[F]{79}

\boilingpoint*[kelvin]{1}
\boilingpoint[kelvin]{1}
\boilingpoint*[K]{1}
\boilingpoint[K]{1}

\boilingpoint*[celsius]{1}
\boilingpoint[celsius]{1}
\boilingpoint*[C]{1}
\boilingpoint[C]{1}

\boilingpoint*[fahrenheit]{1}
\boilingpoint[fahrenheit]{1}
\boilingpoint*[F]{1}
\boilingpoint[F]{1}

\end{document}

enter image description here

5

There you go:

The unit key (default is kelvin) sets the input unit in \DeclareAtomMeltingPoint and output unit for \meltingpoint. Internally the temperature is stored in Kelvin. The number is printed with no further formatting.

Both the declaration with \DeclareAtomMeltingPoint and the usage with \meltingpoint use the atomic number. The element symbol and name is not so easy to retrieve, so the code gets more complicated.

\documentclass{article}

\usepackage{elements}
\usepackage{xparse}

\ExplSyntaxOn
\keys_define:nn { grs / elements }
  {
    , unit .choice:
    , unit / kelvin .code:n = { \cs_set_eq:NN \__grs_select_unit:nnn \use_i:nnn }
    , unit / celsius .code:n = { \cs_set_eq:NN \__grs_select_unit:nnn \use_ii:nnn }
    , unit / fahrenheit .code:n = { \cs_set_eq:NN \__grs_select_unit:nnn \use_iii:nnn }
    , unit .initial:n = kelvin
    , unit .value_required:n = true
  }
\NewDocumentCommand \DeclareAtomMeltingPoint { o m m }
  {
    \group_begin:
      \IfValueT {#1}
        { \keys_set:nn { grs / elements } {#1} }
      \cs_gset:cpx { @elements@atom@meltpoint@ \int_to_roman:n {#2} }
        {
          \__grs_select_unit:nnn
            { \fp_eval:n {#3} } % kelvin
            { \fp_eval:n {#3 + 273.15} } % celsius
            { \fp_eval:n {(#3 + 459.67)*5/9} } % fahrenheit
        }
    \group_end:
  }
\NewDocumentCommand \meltingpoint { o m }
  {
    \group_begin:
      \IfValueT {#1}
        { \keys_set:nn { grs / elements } {#1} }
      \exp_args:Nv \__grs_meltingpoint:n
        { @elements@atom@meltpoint@ \int_to_roman:n {#2} }
    \group_end:
  }
\cs_new:Npn \__grs_meltingpoint:n #1
  {
    \__grs_select_unit:nnn
      { #1 } % kelvin
      { \fp_eval:n {#1 - 273.15} } % celsius
      { \fp_eval:n {#1 * 9/5 - 459.67} } % fahrenheit
  }
\ExplSyntaxOff

\begin{document}

\DeclareAtomMeltingPoint[unit=celsius]{79}{1064}

\meltingpoint[unit=kelvin]{79}

\meltingpoint[unit=celsius]{79}

\meltingpoint[unit=fahrenheit]{79}

\end{document}
  • More thought is needed to use the element symbol or name in \meltingpoint, but it's too late now. If you wish I can do it tomorrow :) – Phelype Oleinik Apr 20 at 3:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.