Possible to get inputnames for variables in a structure? - matlab

This is how the structure is set up:
ClimateSubtractStruct = struct('net',NetClimatologySubtracted,'SW',SWClimatologySubtracted,'LW',LWClimatologySubtracted,'SWCF',SWCFClimatologySubtracted,'LWCF',LWCFClimatologySubtracted,'netclear',netclearClimatologySubtracted,'LWclear',LWclearClimatologySubtracted,'SWclear',SWclearClimatologySubtracted,'Clouds',TotalCloudForcingClimatologySubtracted, 'Precip',PrecipClimatologySubtracted);
fields = fieldnames(ClimateSubtractStruct);
Then I call GlobalCorrMap (which uses the inputnames as arguments for the title and filename of the plot). I then intend to use a for loop to run GlobalCorrMap to compare and plot correlations between each of these variables in the structure. An example argument is below:
GlobalCorrMap(ClimateSubtractStruct.(fields{1}),ClimateSubtractStruct.(fields{3}))
I'm wondering - is it possible for inputname to get the variable name of the variable that's called within structure? Or is it better for me to simply just rename the function so that it can take in the names of the two variables as two separate arguments?

Related

Is it possible to use fsolve if an existing script return a class structure?

I have a script Function.m such that for example, when I write TEST=Function(1,2), I have TEST.x1=4 and TEST.x2=[5,6,7]. I want to use fsolve to help me find input. To be precise, I want to define a function, say a=#(y)Function(1,y)-4 so that when I use [z,vector]=fsolve(#(y)a(y),5), matlab can help me to obtain z=2 and vector=[5,6,7].
I would like to solve it by defining the same structure New_Function.m as Function.m such that it returns x1 values, i.e., TEST=New_Function(1,2) gives TEST=4 only. Then I write new_a=#(y)New_Function(1,y)-4 and solve z=fsolve(#(y)new_a(y),5) and define new_vector=Function(1,z) so that I can access new_vector.x2.
I want to know if it is possible to do my task without defining a new script or amending the content in the existing script. How to write code?
Since Matlab does not allow further referencing the result of a function call, you may need to help yourself with getfield. In your example (provided I got it right), it would be something like New_Func = #(y) getfield(Function(1,y),'x1'). This would take one scalar and return one scalar, i.e., New_Func(y) gives the field value of the struct returned by Function(1,y) associated to the field x1.

Avoiding eval in matlab function

I use the symbolic toolbox in matlab to generate some very long symbolic expressions. Then I use matlabFunction to generate a function file.
Say there are three parameters: p1, p2 and p3.
I have a cell with strings {'p1', 'p2', 'p3'}.
In the derivation of the model I generate symbolic variables p1, p2 and p3 out of them using eval in a loop and stack them in a vector par.
Then when in matlabFunction, I specify par as input.
Moreover, I save the cell string in a .mat file.
Then when I want to simulate this model, I can construct this parameter array using that cell of strings from the .mat file out of 30 available parameters and their values.
Advantages: No need to keep track of the different parameters if I add one to . I can change the order, mess around, but older models still work.
Disadvantage:
Turning things into a function file leads to this error (psi is one of the parameters):
Error: File: f_derive_model.m Line: 96 Column: 5
"psi" previously appeared to be used as a function or
command, conflicting with its use here as the name of a
variable.
A possible cause of this error is that you forgot to
initialize the variable, or you have initialized it
implicitly using load or eval.
Apparently some unnescescary checking is going on because the variable will be intialized in an eval statement.
Question: How can I avoid eval but keep the list of parameters indepent from the model stuff.
Code deriving the long equations:
% Model parameters
mdl.parameters = {'mp','mb','lp','lb','g','d','mP','mM','k','kt'};
par = [];
for i=1:length(mdl.parameters)
eval(strcat(mdl.parameters{i}, '=sym(''', mdl.parameters{i}, "');"));
eval(sprintf(['par = [par;' mdl.parameters{i} '];']));
end
%% Calculate stuff
matlabFunction(MM,'file',[modelName '_mass'],'vars',{par},'outputs',{'M'});
Code using the generated file:
getparams
load('m3d_1')
par = [];
for i=1:length(mdl.parameters)
eval(sprintf(['par = [par;params.' mdl.parameters{i} '];']));
end
See how, as long as I specify the correct value to for example params.mp, it always gets assigned to the input corresponding to the symbolic variable mp in the par vector. I do not want to lose that and have to keep track of the order and so on, nor do I want to call my functions with all the parameters one by one.
Actually, I see nothing wrong in your approach even if the "public opinion" affirms that it's better to avoid using the eval function. An alternative would be using the assignin function as follows:
% use 'caller' instead of 'base' if this code runs within a function
for i = 1:numel(mdl.parameters)
var_name = mdl.parameters{i};
assignin('base',var_name,sym(var_name));
end
In the second case (the one concerning the par variable) I would instead use the getfield function:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = getfield(params,mdl.parameters{i});
end
or, alternatively, this approach:
par_len = numel(mdl.parameters);
par = cell(par_len,1);
for i = 1:par_len
par{i} = params.(mdl.parameters{i});
end

Passing names of functions to another function with parameters as input in MATLAB

Problem Statement: I am trying to write MATLAB code for a main caller function (like run_experiment below) to specify which computations I want to execute where computations are made sequentially using other MATLAB functions. Those other functions are to be evaluated based on parameters passed with the main caller function. The said functions used in computations are to be specified with name of the scripts they are written in.
Example Desired Code Behavior: For example, a command like the following should run the preprocess_data, initialise_model and train_model scripts.
>> run_experiment('dataset_1_options', '|preprocess_data|initialise_model|train_model|');
And this command should run only the train_model script but also evaluates its performance:
>> run_experiment('dataset_1_options', '|train_model|evaluate_model|');
In the above examples "|" is used as a delimiter to specify separate function names to be evaluated. Those functions use the options specified with dataset_1_options. Please do not focus on how to separate that part of the input into meaningful function names; I know how to do it with strsplit.
Constraints and Specifications: The function names to be passed as input to the main caller function are NOT anonymous functions. The purpose is to be able to pass such multiple function names as input AND to evaluate them with the options like the above example. They return output to be evaluated in other parts of the research code (i.e. passing data matrices to other functions within the research code as results of the computations carried out within them.)
Question: Given the desired behavior and constraints mentioned above, can anybody help in how to pass the separate function names from another caller function along with options/parameter to those functions? How should the main caller function evaluate the function names passed in as input with the options specified during the call?
Thank you in advance.
You can pass functions to functions in matlab. You just need to use the # sign when you pass it. In your case it would be run_experiment('dataset_1_options', #train_model) inside a script. You could keep your options in a cell array or something. The run_experiment function would just be a regular function,
function [output] = run_experiment(options, train_model, ...);
train_model(options{1}, ...)
.
.
.
end
What you need to do this is create a cell array with your function names and another array with the corresponding options as below
% Function name array
fn_array = {#fn_1, #fn_2, ...};
% Option array
option_array = {{fn1_opt1, fn2opt2, ...}; {fn2_opt1, fn2_opt2, ...};, ...};
These two need to be passed to your run_experiment function which will evaluate them as below
function run_experiment(fn_array, option_array)
num_fn = length(fn_array); %Finds number of functions to evaluate
for ii = 1:num_fn %Evaluates each function
fn_array{ii}(option_array{ii}{:});
end

Passing multiple inputs into a MATLAB function via loop?

I have multiple variables var_1, var_2, var_3....var_9 (they are named like that) that I want to pass in a function. All of the variables are saved in the workspace. The function takes 2 variables, and spits out an output. I want to compare var_1 with all the variables, including itself, so I prefer to automate it in a loop.
So I want to execute
function(var_1,var_1)--> display answer, function(var_1,var_2)--> display answer...function(var_1,var_9)-->display answer all at once in a loop. I've tried the following, with no luck:
for i=1:7
functionname(var_1,var_'num2str(i)')
end
Where did I go wrong?
You cannot make a dynamic variable name directly. But you can use the eval-function to evaluate an expression as a string. The string can be generated with sprintf and replaces %d with your value.
for i=1:7
eval(sprintf('functionname(var_1,var_%d)', i));
end
But: Whenever you can, you should avoid using the eval function. A much better solution is to use a cell array for this purpose. In the documentation of Matlab there is a whole article about the why and possible alternatives. To make it short, here is the code that uses a cell array:
arr = {val_1, val_2, val_3, val_4, val_5, val_6, val_7, val_8, val_9};
for i = 1:length(arr)
functionname(arr{1},arr{i})
end

Use workspace variables in a Matlab function

I'd like to use the data that are loaded to my workspace in a Matlab function. This is the beginning of my function.
function [totalProfit] = compute(p,exit)
%% Declaration of variables
entry=0;
T = length(data);
.
.
.
end
I'm getting an error:
Undefined function or variable 'data'.
Where is the error?
The variable data was probably defined outside of the function, so it is out of scope.
Pass data as a parameter to compute and then it will be available inside the function.
You can use evalin to work with variables from another workspace. In your example this could be
T = evalin('caller','length(data)')
But please note that in most cases you get cleaner code if you define the variable as input argument for the function. So for your case this would be
function [totalProfit] = compute(p,exit,data)
T = length(data) ;
end
Ran is correct, but I wanted to mention something else. In general, only variables that are passed as arguments to a function are able to be used inside that function, so if you want to use your existing variables inside the function, pass them as input arguments.
It is possible to create global variables which allow you to use them inside functions without passing them as arguments, but it's usually not the best way of writing code. The times where I have used global variables are where I am calling multiple functions from a single script, and I have some constants that will be used by all the functions (for example gravity is a common one). An alternative to global variables is to use a struct, with the variables you want to pass to the function in it, so you only need one extra input argument, but you still have to be a bit careful.