4

I am editing my original question, as I have figured out a method of doing what I want.

Now my question is if there is a more elegant, efficient way to do the following:

Options[f] = {
    Energy -> energy, 
    Temperature -> Func[Energy*Frequency, {Energy, Frequency}], 
    Frequency -> freq
};
f[OptionsPattern[]] := Module[{energy, temperature, frequency},
  energy = OptionValue[Energy];
  frequency = OptionValue[Frequency];
  temperature = If[
    Head[OptionValue[Temperature]] === Func,
    OptionValue[Temperature][[1]] /. Map[# -> OptionValue[#] &,
                     Flatten[{OptionValue[Temperature][[2]]}]],
    OptionValue[Temperature]
    ];
  {
  Energy -> energy,
  Frequency -> frequency, 
  Temperature -> temperature
  }]

Please note that this has the needed generalization to change what options are used as arguments to the passed function or if desired a value (or variable) can be directly inserted as an option.

For this application I have >70 Options (parameters) and I would like to be able to insert (if desired) a function with arguments based on any of the other options, or directly insert a value (if a function "Func" isn't desired.)

Is this more clear?

Thanks again!

M. Decker
  • 111
  • 4
  • Hi and welcome! To make the most of Mma.SE start by taking the [tour] now. As you receive give back, vote and answer questions, keep the site useful, be kind, correct mistakes and share what you have learned. – rhermans Jun 03 '18 at 21:04
  • 2
    You shouldn't use fas a function name and as a paramter as well. Use another symbol for the f inside your function. I would also suggest that using strings for your option names may be safer (i.e. "TemperatureFunction" instead of the plain TemperatureFunction) (see e.g. Why are some option values symbols, other strings?. – MarcoB Jun 03 '18 at 21:17
  • Thanks for the response. Please re-read my original question as I have completely changed it. Hopefully, it is more clear now. – M. Decker Jun 04 '18 at 00:18
  • @M.Decker I have proposed a solution in an answer below. Is that more along the lines of what you seek? – MarcoB Jun 04 '18 at 21:14

2 Answers2

4

Apparently, the only problem was that you scoped f by Module so that OptionValue had a hard time to find the default values for f. (Option stores Option[f] within f, not as DownValue of Option.)

The following should work without any problems.

Options[f] = {
   Energy -> 25,
   Frequency -> 60,
   TemperatureFunction -> 
    Function[{Energy, Frequency}, Energy*Frequency^2]
   };

f[x_, OptionsPattern[]] := Module[{en, freq, tempFunction},
  en = OptionValue[Energy];
  freq = OptionValue[Frequency];
  tempFunction = OptionValue[TemperatureFunction];
  (* **Missing Necessary Code***)
  x*tempFunction[en, freq]
  ]
Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309
  • Thanks for the response. I have edited my question to be more clear on the desired capability I am seeking. I now have a solution, but I am wondering if there is a more elegant (straight forward and efficient) solution.

    Thanks again.

    – M. Decker Jun 04 '18 at 00:19
3

I mentioned in the comments that I find it advantageous to use strings as the names of my user-defined options. In this case, I think it may work for your problem as well. Here is a sample idea:

ClearAll[f]

Options[f] = {
   "Energy" -> energy,
   "Temperature" -> "Energy" "Frequency",
   "Frequency" -> freq
   };

f[OptionsPattern[]] := Module[
  {energy, temperature, frequency},
  energy = OptionValue["Energy"];
  frequency = OptionValue["Frequency"];
  temperature = With[{tempopt = OptionValue["Temperature"]},
    If[NumberQ@tempopt,
      tempopt,
      tempopt /. Cases[tempopt, a_String :> (a -> OptionValue[a]), Infinity]
    ]
   ]
 ]

So now you can pass a "template" to your function, using the names of the other options / parameters as placeholders for their values (you will just have to be careful not to generate recursive definitions upon function call). For instance:

f["Energy" -> aNumber, "Temperature" -> 2 Exp["Energy"] + Log["Frequency"]]

(* Out: 2 E^aNumber + Log[freq] *)

or:

f["Energy" -> 4, "Temperature" -> "Energy" "Frequency"^2]

(* Out: 4 freq^2 *)
MarcoB
  • 67,153
  • 18
  • 91
  • 189
  • I will take a look at this. I would rather not require quotes, but if it end up speeding up calculated results, I'll go with it. Thanks. – M. Decker Jun 06 '18 at 22:03