Function is not defined for 'matlab.ui.Figure' inputs. OTL....
Graphics Functions Return Objects, not Numeric Handles
I mentioned this briefly in Part 2 of this series. Graphics functions now return objects, not numeric handles. The R2014b documentation has detailed information about this subject in the section called Graphics Handles Are Now Objects, Not Doubles. I will give a couple of simple examples to illustrate what can happen with code written before R2014b.
Prior to R2014b, you could store a set of handles to graphics objects in an array and then add some numeric data to that array. In R2014b, that will cause an error.
x = -pi:0.1:pi ;
y1 = sin(x);
y2 = cos(x);
myLines = plot(x,y1,x,y2) % plot returns an array of two Line objects
If you then try to set myLines(3) = 1.2, you get the following error.
Cannot convert double value 1.2 to a handle
MATLAB won't let you add numeric values to an array of graphics objects. A similar problem occurs if you try to use an object handle in a function where MATLAB expects a numeric value. A simple example of this happens with the sprintf function.
a = sprintf('You clicked on figure %d\n', gcf);
The %d specification in the sprintf format string expects an integer value. However, since gcf is a figure object, you get the following error.
Error using sprintf
Function is not defined for 'matlab.ui.Figure' inputs.
Here is one final example. Because graphics handles used to be numbers, you could use them in logical expressions.
if (get(0, 'CurrentFigure'))
disp(['Figure ' get(gcf, 'Name')']) % display the figure name for gcfelse
disp('No open figures') % there is no open figureend
This worked in earlier versions of MATLAB because get(0,'CurrentFigure') would return either an empty array or a numeric figure handle. Both of these values are valid in the logical test of the if statement above. In R2014b, this will cause an error.
Conversion to logical from matlab.ui.Figure is not possible.
We have tried to maintain compatibility with previous releases in some cases. For example, you can still use 0 to refer to the graphics root in functions like get and set. As a best practice, however, we now recommend using the groot function to get the graphics root. Similarly, we still support the use of literal integer values to refer to figures in functions like set, get, and figure. Again, the best practice is to use a variable which contains the object when using these functions.
If you find yourself really stuck, it is possible to cast object handles to numeric handles using the double function. You can then cast the number back to an object handle using the handle function. We don't recommend this as a long term solution. Be aware that we may choose to remove this feature in a future version of MATLAB. If we do, we'll let you know in advance.
Elastomers are increasingly used in industrial applications and understanding their mechanical behavior is even more important than earlier. Tires being one of the largest application of rubbery materials, some of the other very common industrial applications include seals, bearings, dampeners, O-rings etc.
O-rings were invented in the 1890s and used to seal fluids. O-rings are almost present in all industrial and commercial applications and work on the concept of balancing the fluid pressure with the contact stresses. As the fluid pressure increases the O-ring is compressed in the direction normal to the fluid surface as shown in Fig. 01. Elastomers being incompressible, they expand in the transverse direction to increase the contact stresses and effectively seal the interface. The sealing does not fail as long as there is no mechanical failure of the O-ring. This is one of the primary reasons they are still widely used.
Fig 01: O-ring subjected to fluid pressure. The fluid is stopped by the O-ring in (a). As the fluid pressure increases in (b) and (c), the O-ring is pushed in to increase the contact stress and seals the interface.
In this article, we discuss a series of tips for modeling elastomeric materials using the Finite Element Method (FEM) to improve the accuracy and reliability of obtained solutions.
Choosing the right material model for the elastomers
Elastomeric and rubbery materials typically demonstrate:
Isotropic and elastic behavior without any permanent set (like plasticity)
Nonlinear stress-strain behavior as shown in Fig 02.
Different tensile and compressive behavior and comparatively softer in tension
Nearly incompressible behavior with Poisson ratio around 0.4999
Fig 02: Typical nonlinear stress-strain behavior observed in elastomers
Most of these characteristics are captured well through Hyperelastic models and depending on the material behavior a suitable model should be selected. The material parameters are obtained through experiments like uniaxial & biaxial tensile test, uniaxial compression test, planar & simple shear and volumetric test. A more detailed discussion on the selection of hyperelastic material model can be found on the SimScale blog.
Tip 01: Using the parameters highlighted in this blog article, choosing the right hyperelastic material model is half the job done well.
Meshing the structure
At present, SimScale allows for the meshing of the structures with Tetrahedrons. Hence, in this article, we will limit the discussion to meshing 3D structures with tetrahedrons. A general overview on meshing & meshing tutorial is available in the SimScale documentation. Presently, SimScale allows tetrahedral meshing with following options:
Automatic
Parametric
Tetrahedral with local refinement
As shown in Fig. 03, all these cases allow for the specification of mesh order: first or second. Using a first-order generates a mesh with four-noded tetrahedral elements and second-order a mesh with ten-noded tetrahedral elements. For more detailed tips on meshing for structural mechanics problems, watch out for upcoming articles.
Fig 03: Order of interpolation
Tip 02: For most elastomeric structures second order would be the safe choice. However, in some cases, a first-order mesh could also be sufficient and save significant computational time.
Considering geometry & loading
The dimensions of the structure also play a pertinent role in the accuracy of solutions obtained. Many of the applications of elastomers, like conveyor belts, have one or more dimensions (like length & breadth) much larger than the others (thickness).
For example, as shown in Fig. 04, if the thickness and breadth of the structure are much larger than its length, then it can be considered as a beam. Similarly, if the thickness is much smaller than both length & breadth, then the structure can be considered as a plate or shell. If all the dimensions are comparable, then the structure can be considered to be a full solid. Irrespective of the structure type, solid elements are being used to mesh the structure. Thus, is becomes important to understand the form of a structure being considered so that effective meshes can be generated.
Fig 04: Illustration of beam, plate, shell & solid structures
It is important to first identify the category of the structure. For solid structures, the automatic tetrahedral meshing can be directly used and both the first and second order could yield good results. However, the complexity arises for structures that resemble beams / plates / shells.
Secondly, in addition to geometry, it is also important to identify the type of loading these structures are subjected to. For example, the O-ring illustration shows that the loading on the elastomer structure is of bending-type in nature.
When the structures are of the form of beams-plates-shells, they can be considered as thin structures. These thin-structures demonstrate a locking effect (well known as shear locking) especially when a first-order mesh is used and structure is subjected to bending loads. The easiest way to circumvent the shear locking is through mesh refinement or using higher-order elements. A more detailed discussion on the shear locking is dealt in detail in our upcoming blog article on meshing tips for structural mechanics problems.
Tip 03: If you are using a solid structure, first-order might still work. If the structure can be classified as one of the thin structures and/or subjected to bending loads, then second-order mesh is strongly recommended.
Dealing with incompressibility in elastomers
Most elastomers and rubbers have a Poisson ratio of almost 0.5. Physically, this means that when the material undergoes elongation in the x-direction, then there is enough compression in the other two directions such that the initial and final volumes remain same. Note that a Poisson ratio of 0.5 is equivalent to saying that the Bulk modulus is infinity.
Fig 05: Relation between bulk modulus a young’s modulus. As Poisson ratio reaches 0.5, bulk modulus tends to infinity
Or otherwise, this means that it would take an infinite amount of energy to compress the material. To get a feel of the idea, one could consider water. Water is a perfect example of an incompressible material. If one would fill a can with water and try to compress, it can be seen that the volume of water remains unchanged. So one could say that the bulk modulus of water is almost infinity. Since infinity cannot be used numerically, a very large bulk modulus is used to signify Poisson ratio tending to 0.5.
When the bulk modulus is considered such that the Poisson ratio is larger than 0.4, most normal elements show a locking effect. This is commonly known as volumetric locking. Unlike the earlier discussed shear locking, volumetric locking cannot be circumvented through mesh refinement. Volumetric locking is not only common to elastomers but also pertinent to any elastoplastic material.
There are several approaches available in the literature:
Selectively reduced integration (B-Bar method)
Uniformly reduced integration (or more commonly just known as reduced integration)
Enhanced strain formulation
Mixed formulations
First, it would be important to understand the cause of this volumetric locking before finding a solution. Considering a simple example of a loaded structure made of elastomer in 2-D, as shown in Fig 05, the cause of volumetric deformation is observed. The mesh is made of two triangles (or could be one quadrilateral either) with linear interpolation (first-order mesh). A small force (or alternatively displacement) is applied on the free node (node number 01) along the direction of 45-deg.
Fig 05: Illustration of volumetric locking
Since the material is volume preserving and the elements use linear interpolation (i.e. lines 1-2 and 1-4 need to be straight), the only direction the free node can move is along the circle shown in red color. However, this would mean moving perpendicular to the effective reaction force and such a motion cannot be allowed. Eventually, the only possible solution is the trivial solution of nodal displacements being zero (or very small numerically). This is clearly disastrous!
One of the simplest ways to solve the problem is using second (or higher) order elements. When second-order elements are used, the edges do not need to be straight anymore. This would facilitate motions that could lead to non-zero nodal displacements and still conserve the volume. However, as the Poisson ratio approaches 0.499, 0.4995 etc, even the second-order elements do not behave well. To understand this behavior of second-order elements, it is important to understand the mathematics behind the interface.
In problems involving elastomers (or nonlinear FEM), matrix equations [K]{u} – {f} = {R} are solved such that {R} tends to zero. The stiffness matrix [K] is first computed locally for each element and then assembled to a bigger global system. Locally, in each element, [K] is computed at fictitious points commonly known as Gauss (or integration) points. The above problem with second-order elements is caused since the volumetric strain is being enforced to be zero at all of these integration points. The total energy from volumetric strain can be approximately written as a product of Bulk modulus x (volumetric strain)^2. Since the bulk modulus is very large, even a small volumetric strain can lead to large extra addition to the energy. This renders the total equation system to behave very stiff and the solvers more often converge to the trivial solution (of zero displacements).
An alternative and very commonly used approach, also incorporated in SimScale, is using reduced integration with second-order elements. This means that the deviatoric strains are computed as earlier but the zero volumetric strain is enforced only at certain points. Though this might sound to be inaccurate, reduced integration has been observed to be extremely robust and yield quite accurate solutions across a wide range of Poisson ratio.
Note that first-order tetrahedrons use only one integration point and thus a reduced integration with these elements is not possible.
Tip 04: If the Poisson ratio is less than or equal to 0.4, first order elements can be used. For Poisson ratio’s even up to 0.45, second-order tetrahedrons could work well. For much higher Poisson ratios, it is strongly recommended to use second-order elements with reduced integration.
Force vs. displacement boundary condition for modeling elastomers
One of the common causes of non-convergence is unbalanced residuals. When modeling elastomers, the system of equation being solved is nonlinear, i.e. [K(u)] {u} – {f} = {R}. Here the stiffness matrix [K(u)] is a function of the unknowns {u}. Thus, small displacements / forces are applied in small increments to reach the desired value.
Using smaller time steps (i.e. smaller force increments) can significantly improve the convergence properties. Alternatively, if possible, displacement controlled boundary conditions are most likely a safe option. As shown in Fig 05, where a very highly nonlinear problem is considered, for every displacement there is a unique solution of the force. However, the same is not true vice-versa.
Fig 05: Nonlinear force-displacement curve showing that for a particular force there can be multiple displacements (or non-unique solution). But for each displacement, there is only one force (or a unique solution).
This means that when a force boundary condition is applied, it need not lead to a unique displacement. Such non-uniqueness can easily lead to a lack of convergence. Alternatively, using a displacement boundary condition can likely lead to better convergence. In such cases, advanced techniques like line search etc are employed to improve the overall convergence of the system. Watch out our SimScale blog for the upcoming article related to solvers for structural mechanics problems that will delve more into areas like line search etc.
Tip 05: If possible, use displacement boundary conditions.
Convergence issues
There are several reasons why a simulation can fail and show a lack of convergence. Some of the very common ones pertaining to elastomers include, but not limited to,
Material instability
Time step size
Inelastic effects
Material instability
The material parameters are generally obtained by fitting the experimental data. The fitting is limited by the maximum stretch to which the data is available. If the model is used beyond this limit, the model might not be unconditionally stable.
For example: Say if the data was only available for a stretch to 30% and the model parameters were fitted with this. When a simulation is done using this model where the strains are much larger (> 30%), it is possible that the nonlinear behavior beyond 30% is not accurately captured.
Secondly, depending on the number of tests used for fitting, it is possible that the material demonstrates an instability when subjected to a different type of loading. For example: Say material parameters for Mooney-Rivlin model are fitted using only uniaxial tests. When a biaxial simulation is done, it is possible that the results show significant instabilities.
A possible solution to this would be to test the material model with uniaxial, biaxial, shear, volumetric tests for up to failure limits. Using these simulations, possible points of material instabilities can be identified a priori.
Time step size
The second possible reason for the lack of convergence can be time step size. If a manual time step is used and if the time step is too large then it can lead to a lack of convergence. SimScale allows for auto time-stepping and it is recommended to use auto-stepping.
Fig 06: Screenshot for auto time stepping
As shown in Fig. 06, a retiming event is used to kick-in to reduce the time step. When the time step is too large and leads to non-convergence, this kicks in a retiming event. In such a case, the time step is reduced and the simulation restarts from the last converged time step. This significantly reduces the failure of simulations. There are several options available for time step calculation type and “Newton Iterations Target” option is a good place to start.
Inelastic effect
In this article, we have considered the elastomers to be purely hyperelastic and we will discuss the effects of inelasticity in an upcoming blog article
Tip 06: Check the material parameters thoroughly for instability before using it under general loading conditions. Auto time stepping is a great option to prevent failure of simulations!
Overall, summarizing the type of problem or procedure, types of element recommended and to avoid are:
Last week, in Part 1 of this post, I discussed three tips to consider when solving a detailed stress analysis of an O-ring or seal, including: material testing, material law selection, and testing of the selected material law . This week, I'll discuss four more tips for enhancing the accuracy and convergence of your simulation!
4) Element Formulation: Selecting the best element formulation is another key modeling decision, especially when analyzing parts in compression where element locking is of concern. Mike Bak’s blog “Dealing with Incompressibility” provides excellent guidance to follow for these types of analyses.
5) Mesh: With hyperelastic materials, the deformed element shapes are more important than the initial element shapes. Plan for the deformation by skewing the undeformed mesh to distort into more of a regular pattern. Lower order elements are more stable, and often an all-triangular lower order mesh is recommended to overcome excessive element distortion. A finer mesh might not always be better, since small elements in the areas of peak strain often become more distorted than with a coarser mesh and thus are more susceptible to element failure. Consider rezoning if excess element distortion cannot be avoided in the undeformed mesh. Figure 3 above illustrates an axisymmetric seal simulation where automated progressive rezoning is used to capture the significant seal distortion and provide the accurate refined mesh in the final stages of the simulation.
6) Load control: Use a displacement controlled solution if possible, and force a large number of sub-steps since cumulative unbalanced residuals are a common cause of non-convergence. By using small load steps, one can minimize these errors and accurately track the large deflections and material nonlinearities.
7) Adjust the volume compatibility constraint: This is typically an analysis control parameter that allows for some error in volumetric compatibility. In ANSYS, the default for the Vtolparameter is 1e-5. Adjusting this parameter on the ANSYS SOLC command to a value as low as 1e-2 can sometimes be the key in overcoming convergence issues when large compressive strains are encountered.
What challenges have you overcome when modeling rubber materials? I would love to hear other tips and tricks for solving these complex analyses.
Are you having problems solving a detailed stress analysis of an O-ring or seal? This post provides a series of tips for enhancing the accuracy and convergence of your simulation.
Materials such as rubber or elastomers are typically modeled with Hyperelastic constitutive models because they typically exhibit the following characteristics:
By definition, the material behavior is elastic, where there is no permanent set, and the material loads and unloads up and down the same stress-strain curve.
The relationship between stress and strain is highly nonlinear and typically softer in tension vs. compression. The tension portion of the stress-strain curve often has an initial softening slope before significant stiffening, while the compressive part of the curve is quite a bit stiffer. (See Figure 1 above.)
There is little volume change in the material and thus it acts as either fully or nearly fully incompressible. This would be equivalent to setting Poisson’s ratio to 0.499.. in a linear elastic model, which creates an incompressible material response.
The material response is isotropic and isothermal (stress vs. strain and thermal expansion coefficients are the same in all directions)
Obtaining both an accurate and converged solution in any nonlinear analysis is a challenge. Here are my top three tips, in order of importance, specifically associated with modeling hyperelastic materials. I’ll reveal four more tips in Part 2 of this post, so stay tuned!
1)Material Testing: Accurate material test data is a must when simulating the large strain response of rubber and elastomer materials. At least two material tests from the list below are needed to get good calibration between test and computer model.
Uniaxial Tension
Uniaxial Compression
Biaxial Tension (Circular or rectangular specimen)
Planar Shear
Simple Shear
Volumetric Test (Button specimen)
The test data should represent, as closely as possible, the in-situ material properties. Because, manufacturing processes, such as the rate of injection molding, can change the final material characteristics.
2) Material Law Selection: There are many materials laws available to simulate hyperelastic materials using finite elements. Some of the more common laws include Mooney-Rivlin, Ogden, Yeoh, Blatz-Ko, Arruda-Boyce. Selecting the best material law plays an import role in the success of your analysis. Select a material law with the best curve fit over the range of expected stresses and strains. This topic has been discussed in a previous CAE Associates Blog post. Selecting the best material law can be a bit of trial and error process using test data curve fit compatibility and solution robustness (see item 3 below) as selection criteria.
I would suggest starting with the simpler laws first, such as the two term Mooney Rivlin, and also be cognitive of the expected strain levels in your simulation. For example, if you don’t expect any strains to exceed 30%, there is no reason to look to match strains at 300%, since these will never be encountered in the real problem. Some FEA codes have automated curve fitting capabilities that can be used to quickly test a number of different laws and automatically determine the necessary law coefficients. ANSYS Workbench’s engineering data curve fitting is illustrated in Figure 2, where four laws are compared with each being the better fit to test data, depending on the anticipated simulation response.
Figure 2: ANSYS Engineering Data Comparison of Hyperelastic Material Law Curve Fitting
3) Test the Material Law: The one element test case should be used to determine the robustness of the material model by imposing tension, compression and shear loads on both regular and irregular single element shapes. When comparing to test data be sure to convert the test data from engineering to true stress / log strain for direct comparison with FEA results. Comparing the convergence efficiency between multiple material models on the single element model can be the deciding factor when more than one material law might fit the test data adequately by saving significant CPU time and convergence headaches with the real model.
Watch for Part 2 of this post. Tips 4 - 7 will include some great information about element formulation, meshing and loading. If you have any of your own tips, please share them below in the comments!
C = bsxfun(fun,A,B) applies the element-by-element binary operation specified by the function handle fun to arrays A and B, with singleton expansion enabled. fun can be one of the following built-in functions:
@plus
Plus
@minus
Minus
@times
Array multiply
@rdivide
Right array divide
@ldivide
Left array divide
@power
Array power
@max
Binary maximum
@min
Binary minimum
@rem
Remainder after division
@mod
Modulus after division
@atan2
Four-quadrant inverse tangent; result in radians
@atan2d
Four-quadrant inverse tangent; result in degrees
@hypot
Square root of sum of squares
@eq
Equal
@ne
Not equal
@lt
Less than
@le
Less than or equal to
@gt
Greater than
@ge
Greater than or equal to
@and
Element-wise logical AND
@or
Element-wise logical OR
@xor
Logical exclusive OR
fun = @(A,B) A.*sin(B);
A = 1:7;
B = pi*[0 1/4 1/3 1/2 2/3 3/4 1].';
C = bsxfun(fun,A,B)
You can create function handles to named and anonymous functions. You can store multiple function handles in an array, and save and load them, as you would any other variable.
What Is a Function Handle?
A function handle is a MATLAB® data type that stores an association to a function. Indirectly calling a function enables you to invoke the function regardless of where you call it from. Typical uses of function handles include:
Pass a function to another function (often called function functions). For example, passing a function to integration and optimization functions, such as integral and fzero.
Specify callback functions. For example, a callback that responds to a UI event or interacts with data acquisition hardware.
Construct handles to functions defined inline instead of stored in a program file (anonymous functions).
Call local functions from outside the main function.
You can see if a variable, h, is a function handle using isa(h,'function_handle').
Creating Function Handles
To create a handle for a function, precede the function name with an @ sign. For example, if you have a function called myfunction, create a handle named f as follows:
f = @myfunction;
You call a function using a handle the same way you call the function directly. For example, suppose that you have a function named computeSquare, defined as:
function y = computeSquare(x)
y = x.^2;
end
Create a handle and call the function to compute the square of four.
f = @computeSquare;
a = 4;
b = f(a)
b =
16
If the function does not require any inputs, then you can call the function with empty parentheses, such as
h = @ones;
a = h()
a =
1
Without the parentheses, the assignment creates another function handle.
a = h
a =
@ones
Function handles are variables that you can pass to other functions. For example, calculate the integral of x2 on the range [0,1].
q = integral(f,0,1);
Function handles store their absolute path, so when you have a valid handle, you can invoke the function from any location. You do not have to specify the path to the function when creating the handle, only the function name.
Keep the following in mind when creating handles to functions:
Name length — Each part of the function name (including package and class names) must be less than the number specified by namelengthmax. Otherwise, MATLAB truncates the latter part of the name.
Scope — The function must be in scope at the time you create the handle. Therefore, the function must be on the MATLAB path or in the current folder. Or, for handles to local or nested functions, the function must be in the current file.
Precedence — When there are multiple functions with the same name, MATLAB uses the same precedence rules to define function handles as it does to call functions. For more information, see Function Precedence Order.
Overloading — If the function you specify overloads a function in a class that is not a fundamental MATLAB class, the function is not associated with the function handle at the time it is constructed. Instead, MATLAB considers the input arguments and determines which implementation to call at the time of evaluation.
Anonymous Functions
You can create handles to anonymous functions. An anonymous function is a one-line expression-based MATLAB function that does not require a program file. Construct a handle to an anonymous function by defining the body of the function, anonymous_function, and a comma-separated list of input arguments to the anonymous function, arglist. The syntax is:
h = @(arglist)anonymous_function
For example, create a handle, sqr, to an anonymous function that computes the square of a number, and call the anonymous function using its handle.
sqr = @(n) n.^2;
x = sqr(3)
x =
9
For more information, see Anonymous Functions.
Arrays of Function Handles
You can create an array of function handles by collecting them into a cell or structure array. For example, use a cell array:
C = {@sin, @cos, @tan};
C{2}(pi)
ans =
-1
Or use a structure array:
S.a = @sin; S.b = @cos; S.c = @tan;
S.a(pi/2)
ans =
1
Saving and Loading Function Handles
You can save and load function handles in MATLAB, as you would any other variable. In other words, use the save and load functions. If you save a function handle, MATLAB does not save the path information. If you load a function handle, and the function file no longer exists on the path, the handle is invalid. An invalid handle occurs if the file location or file name has changed since you created the handle. If a handle is invalid, MATLAB still performs the load successfully and without displaying a warning. However, when you invoke the handle, MATLAB issues an error.
Nested Functions
What Are Nested Functions?
A nested function is a function that is completely contained within a parent function. Any function in a program file can include a nested function.
For example, this function named parent contains a nested function named nestedfx:
function parent
disp('This is the parent function')
nestedfx
function nestedfx
disp('This is the nested function')
end
end
The primary difference between nested functions and other types of functions is that they can access and modify variables that are defined in their parent functions. As a result:
Nested functions can use variables that are not explicitly passed as input arguments.
In a parent function, you can create a handle to a nested function that contains the data necessary to run the nested function.
Requirements for Nested Functions
Typically, functions do not require an end statement. However, to nest any function in a program file, all functions in that file must use an end statement.
You cannot define a nested function inside any of the MATLAB® program control statements, such as if/elseif/else, switch/case, for, while, or try/catch.
You must call a nested function either directly by name (without using feval), or using a function handle that you created using the @ operator (and not str2func).
All of the variables in nested functions or the functions that contain them must be explicitly defined. That is, you cannot call a function or script that assigns values to variables unless those variables already exist in the function workspace. (For more information, see Variables in Nested and Anonymous Functions.)
Sharing Variables Between Parent and Nested Functions
In general, variables in one function workspace are not available to other functions. However, nested functions can access and modify variables in the workspaces of the functions that contain them.
This means that both a nested function and a function that contains it can modify the same variable without passing that variable as an argument. For example, in each of these functions, main1 and main2, both the main function and the nested function can access variable x:
function main1
x = 5;
nestfun1
function nestfun1
x = x + 1;
end
end
function main2
nestfun2
function nestfun2
x = 5;
end
x = x + 1;
end
When parent functions do not use a given variable, the variable remains local to the nested function. For example, in this function named main, the two nested functions have their own versions of x that cannot interact with each other:
function main
nestedfun1
nestedfun2
function nestedfun1
x = 1;
end
function nestedfun2
x = 2;
end
end
Functions that return output arguments have variables for the outputs in their workspace. However, parent functions only have variables for the output of nested functions if they explicitly request them. For example, this function parentfun does not have variable y in its workspace:
function parentfun
x = 5;
nestfun;
function y = nestfun
y = x + 1;
end
end
If you modify the code as follows, variable z is in the workspace of parentfun:
function parentfun
x = 5;
z = nestfun;
function y = nestfun
y = x + 1;
end
end
Using Handles to Store Function Parameters
Nested functions can use variables from three sources:
Input arguments
Variables defined within the nested function
Variables defined in a parent function, also called externally scoped variables
When you create a function handle for a nested function, that handle stores not only the name of the function, but also the values of externally scoped variables.
For example, create a function in a file named makeParabola.m. This function accepts several polynomial coefficients, and returns a handle to a nested function that calculates the value of that polynomial.
function p = makeParabola(a,b,c)
p = @parabola;
function y = parabola(x)
y = a*x.^2 + b*x + c;
end
end
The makeParabola function returns a handle to the parabola function that includes values for coefficients a, b, and c.
At the command line, call the makeParabola function with coefficient values of 1.3, .2, and 30. Use the returned function handle p to evaluate the polynomial at a particular point:
p = makeParabola(1.3,.2,30);
X = 25;
Y = p(X)
Y =
847.5000
Many MATLAB functions accept function handle inputs to evaluate functions over a range of values. For example, plot the parabolic equation from -25 to +25:
fplot(p,[-25,25])
You can create multiple handles to the parabola function that each use different polynomial coefficients:
firstp = makeParabola(0.8,1.6,32);
secondp = makeParabola(3,4,50);
range = [-25,25];
figure
hold on
fplot(firstp,range)
fplot(secondp,range,'r:')
hold off
Visibility of Nested Functions
Every function has a certain scope, that is, a set of other functions to which it is visible. A nested function is available:
From the level immediately above it. (In the following code, function A can call B or D, but not C or E.)
From a function nested at the same level within the same parent function. (Function B can call D, and D can call B.)
From a function at any lower level. (Function C can call B or D, but not E.)
function A(x, y) % Main function
B(x,y)
D(y)
function B(x,y) % Nested in A
C(x)
D(y)
function C(x) % Nested in B
D(x)
end
end
function D(x) % Nested in A
E(x)
function E(x) % Nested in D
disp(x)
end
end
end
The easiest way to extend the scope of a nested function is to create a function handle and return it as an output argument, as shown in Using Handles to Store Function Parameters. Only functions that can call a nested function can create a handle to it.
Anonymous Functions
What Are Anonymous Functions?
An anonymous function is a function that is not stored in a program file, but is associated with a variable whose data type is function_handle. Anonymous functions can accept inputs and return outputs, just as standard functions do. However, they can contain only a single executable statement.
For example, create a handle to an anonymous function that finds the square of a number:
sqr = @(x) x.^2;
Variable sqr is a function handle. The @ operator creates the handle, and the parentheses () immediately after the @ operator include the function input arguments. This anonymous function accepts a single input x, and implicitly returns a single output, an array the same size as x that contains the squared values.
Find the square of a particular value (5) by passing the value to the function handle, just as you would pass an input argument to a standard function.
a = sqr(5)
a =
25
Many MATLAB® functions accept function handles as inputs so that you can evaluate functions over a range of values. You can create handles either for anonymous functions or for functions in program files. The benefit of using anonymous functions is that you do not have to edit and maintain a file for a function that requires only a brief definition.
For example, find the integral of the sqr function from 0 to 1 by passing the function handle to the integral function:
q = integral(sqr,0,1);
You do not need to create a variable in the workspace to store an anonymous function. Instead, you can create a temporary function handle within an expression, such as this call to the integral function:
q = integral(@(x) x.^2,0,1);
Variables in the Expression
Function handles can store not only an expression, but also variables that the expression requires for evaluation.
For example, create a function handle to an anonymous function that requires coefficients a, b, and c.
a = 1.3;
b = .2;
c = 30;
parabola = @(x) a*x.^2 + b*x + c;
Because a, b, and c are available at the time you create parabola, the function handle includes those values. The values persist within the function handle even if you clear the variables:
clear a b c
x = 1;
y = parabola(x)
y =
31.5000
To supply different values for the coefficients, you must create a new function handle:
a = -3.9;
b = 52;
c = 0;
parabola = @(x) a*x.^2 + b*x + c;
x = 1;
y = parabola(1)
y =
48.1000
You can save function handles and their associated values in a MAT-file and load them in a subsequent MATLAB session using the save and load functions, such as
save myfile.mat parabola
Use only explicit variables when constructing anonymous functions. If an anonymous function accesses any variable or nested function that is not explicitly referenced in the argument list or body, MATLAB throws an error when you invoke the function. Implicit variables and function calls are often encountered in the functions such as eval, evalin, assignin, and load. Avoid using these functions in the body of anonymous functions.
Multiple Anonymous Functions
The expression in an anonymous function can include another anonymous function. This is useful for passing different parameters to a function that you are evaluating over a range of values. For example, you can solve the equation
for varying values of c by combining two anonymous functions:
g = @(c) (integral(@(x) (x.^2 + c*x + 1),0,1));
Here is how to derive this statement:
Write the integrand as an anonymous function,
@(x) (x.^2 + c*x + 1)
Evaluate the function from zero to one by passing the function handle to integral,
integral(@(x) (x.^2 + c*x + 1),0,1)
Supply the value for c by constructing an anonymous function for the entire equation,
g = @(c) (integral(@(x) (x.^2 + c*x + 1),0,1));
The final function allows you to solve the equation for any value of c. For example:
g(2)
ans =
2.3333
Functions with No Inputs
If your function does not require any inputs, use empty parentheses when you define and call the anonymous function. For example:
t = @() datestr(now);
d = t()
d =
26-Jan-2012 15:11:47
Omitting the parentheses in the assignment statement creates another function handle, and does not execute the function:
d = t
d =
@() datestr(now)
Functions with Multiple Inputs or Outputs
Open This Example
Anonymous functions require that you explicitly specify the input arguments as you would for a standard function, separating multiple inputs with commas. For example, this function accepts two inputs, x and y:
myfunction = @(x,y) (x^2 + y^2 + x*y);
x = 1;
y = 10;
z = myfunction(x,y)
z =
111
However, you do not explicitly define output arguments when you create an anonymous function. If the expression in the function returns multiple outputs, then you can request them when you call the function. Enclose multiple output variables in square brackets.
For example, the ndgrid function can return as many outputs as the number of input vectors. This anonymous function that calls ndgrid can also return multiple outputs:
c = 10;
mygrid = @(x,y) ndgrid((-x:x/c:x),(-y:y/c:y));
[x,y] = mygrid(pi,2*pi);
You can use the output from mygrid to create a mesh or surface plot:
z = sin(x) + cos(y);
mesh(x,y,z)
Arrays of Anonymous Functions
Although most MATLAB fundamental data types support multidimensional arrays, function handles must be scalars (single elements). However, you can store multiple function handles using a cell array or structure array. The most common approach is to use a cell array, such as
f = {@(x)x.^2;
@(y)y+10;
@(x,y)x.^2+y+10};
When you create the cell array, keep in mind that MATLAB interprets spaces as column separators. Either omit spaces from expressions, as shown in the previous code, or enclose expressions in parentheses, such as
f = {@(x) (x.^2);
@(y) (y + 10);
@(x,y) (x.^2 + y + 10)};
Access the contents of a cell using curly braces. For example, f{1} returns the first function handle. To execute the function, pass input values in parentheses after the curly braces:
x = fzero(fun,x0) tries to find a point x where fun(x) = 0. This solution is where fun(x) changes sign—fzero cannot find a root of a function such as x^2.
example
x = fzero(fun,x0,options) uses options to modify the solution process.
example
x = fzero(problem) solves a root-finding problem specified by problem.
example
[x,fval,exitflag,output] = fzero(___) returns fun(x) in the fval output, exitflag encoding the reason fzero stopped, and an output structure containing information on the solution process.
Examples
collapse all
Root Starting From One Point
Open This Example
Calculate $\pi$ by finding the zero of the sine function near 3.
fun = @sin; % function
x0 = 3; % initial point
x = fzero(fun,x0)
x =
3.1416
Root Starting From an Interval
Open This Example
Find the zero of cosine between 1 and 2.
fun = @cos; % function
x0 = [1 2]; % initial interval
x = fzero(fun,x0)
x =
1.5708
Note that $\cos(1)$ and $\cos(2)$ differ in sign.
Root of a Function Defined by a File
Find a zero of the function f(x) = x3 – 2x – 5.
First, write a file called f.m.
function y = f(x)
y = x.^3 - 2*x - 5;
Save f.m on your MATLAB® path.
Find the zero of f(x) near 2.
fun = @f; % function
x0 = 2; % initial point
z = fzero(fun,x0)
z =
2.0946
Since f(x) is a polynomial, you can find the same real zero, and a complex conjugate pair of zeros, using the roots command.
roots([1 0 -2 -5])
ans =
2.0946
-1.0473 + 1.1359i
-1.0473 - 1.1359i
Root of Function with Extra Parameter
Open This Example
Find the root of a function that has an extra parameter.
myfun = @(x,c) cos(c*x); % parameterized function
c = 2; % parameter
fun = @(x) myfun(x,c); % function of x alone
x = fzero(fun,0.1)
x =
0.7854
Nondefault Options
Open This Example
Plot the solution process by setting some plot functions.
Define the function and initial point.
fun = @(x)sin(cosh(x));
x0 = 1;
Examine the solution process by setting options that include plot functions.
To include extra parameters in your function, see the example Root of Function with Extra Parameter and the section Parameterizing Functions.
Example: @sin
Example: @myFunction
Example: @(x)(x-a)^5 - 3*x + a - 1
Data Types: function_handle
x0 — Initial value
scalar | 2-element vector
Initial value, specified as a real scalar or a 2-element real vector.
Scalar — fzero begins at x0 and tries to locate a point x1 where fun(x1) has the opposite sign of fun(x0). Then fzero iteratively shrinks the interval where fun changes sign to reach a solution.
2-element vector — fzero checks that fun(x0(1)) and fun(x0(2)) have opposite signs, and errors if they do not. It then iteratively shrinks the interval where fun changes sign to reach a solution. An interval x0 must be finite; it cannot contain ±Inf.
Tip Calling fzero with an interval (x0 with two elements) is often faster than calling it with a scalar x0.
Example: 3
Example: [2,17]
Data Types: double
options — Options for solution process
structure, typically created using optimset
Options for solution process, specified as a structure. Create or modify the options structure using optimset. fzero uses these options structure fields.
Display
Level of display:
'off' displays no output.
'iter' displays output at each iteration.
'final' displays just the final output.
'notify' (default) displays output only if the function does not converge.
FunValCheck
Check whether objective function values are valid.
'on' displays an error when the objective function returns a value that is complex, Inf, or NaN.
The default, 'off', displays no error.
OutputFcn
Specify one or more user-defined functions that an optimization function calls at each iteration, either as a function handle or as a cell array of function handles. The default is none ([]). See Output Functions.
PlotFcns
Plot various measures of progress while the algorithm executes. Select from predefined plots or write your own. Pass a function handle or a cell array of function handles. The default is none ([]).
@optimplotx plots the current point.
@optimplotfval plots the function value.
For information on writing a custom plot function, see Plot Functions.
TolX
Termination tolerance on x, a positive scalar. The default is eps, 2.2204e–16.
Example: options = optimset('FunValCheck','on')
Data Types: struct
problem — Root-finding problem
structure
Root-finding problem, specified as a structure with all of the following fields.
objective
Objective function
x0
Initial point for x, real scalar or 2-element vector
solver
'fzero'
options
Options structure, typically created using optimset
For an example, see Solve Problem Structure.
Data Types: struct
Output Arguments
collapse all
x — Location of root or sign change
real scalar
Location of root or sign change, returned as a scalar.
fval — Function value at x
real scalar
Function value at x, returned as a scalar.
exitflag — Integer encoding the exit condition
integer
Integer encoding the exit condition, meaning the reason fzero stopped its iterations.
1
Function converged to a solution x.
-1
Algorithm was terminated by the output function or plot function.
-3
NaN or Inf function value was encountered while searching for an interval containing a sign change.
-4
Complex function value was encountered while searching for an interval containing a sign change.
-5
Algorithm might have converged to a singular point.
-6
fzero did not detect a sign change.
output — Information about root-finding process
structure
Information about root-finding process, returned as a structure. The fields of the structure are:
intervaliterations
Number of iterations taken to find an interval containing a root
iterations
Number of zero-finding iterations
funcCount
Number of function evaluations
algorithm
'bisection, interpolation'
message
Exit message
Solving a Nonlinear Equation in One Variable
The fzero function attempts to find a root of one equation with one variable. You can call this function with either a one-element starting point or a two-element vector that designates a starting interval. If you give fzero a starting point x0, fzero first searches for an interval around this point where the function changes sign. If the interval is found, fzero returns a value near where the function changes sign. If no such interval is found, fzero returns NaN. Alternatively, if you know two points where the function value differs in sign, you can specify this starting interval using a two-element vector; fzero is guaranteed to narrow down the interval and return a value near a sign change.
The following sections contain two examples that illustrate how to find a zero of a function using a starting interval and a starting point. The examples use the function humps.m, which is provided with MATLAB®. The following figure shows the graph of humps.
x = -1:.01:2;
y = humps(x);
plot(x,y)
xlabel('x');
ylabel('humps(x)')
grid on
Setting Options For fzero
You can control several aspects of the fzero function by setting options. You set options using optimset. Options include:
Choosing the amount of display fzero generates — see Set Options, Using a Starting Interval, and Using a Starting Point.
Choosing various tolerances that control how fzero determines it is at a root — see Set Options.
Choosing a plot function for observing the progress of fzero towards a root — see Plot Functions.
Using a custom-programmed output function for observing the progress of fzero towards a root — see Output Functions.
Using a Starting Interval
The graph of humps indicates that the function is negative at x = -1 and positive at x = 1. You can confirm this by calculating humps at these two points.
humps(1)
ans =
16
humps(-1)
ans =
-5.1378
Consequently, you can use [-1 1] as a starting interval for fzero.
The iterative algorithm for fzero finds smaller and smaller subintervals of [-1 1]. For each subinterval, the sign of humps differs at the two endpoints. As the endpoints of the subintervals get closer and closer, they converge to zero for humps.
To show the progress of fzero at each iteration, set the Display option to iter using the optimset function.
options = optimset('Display','iter');
Then call fzero as follows:
a = fzero(@humps,[-1 1],options)
Func-count x f(x) Procedure
2 -1 -5.13779 initial
3 -0.513876 -4.02235 interpolation
4 -0.513876 -4.02235 bisection
5 -0.473635 -3.83767 interpolation
6 -0.115287 0.414441 bisection
7 -0.115287 0.414441 interpolation
8 -0.132562 -0.0226907 interpolation
9 -0.131666 -0.0011492 interpolation
10 -0.131618 1.88371e-07 interpolation
11 -0.131618 -2.7935e-11 interpolation
12 -0.131618 8.88178e-16 interpolation
13 -0.131618 8.88178e-16 interpolation
Zero found in the interval [-1, 1]
a =
-0.1316
Each value x represents the best endpoint so far. The Procedure column tells you whether each step of the algorithm uses bisection or interpolation.
You can verify that the function value at a is close to zero by entering
humps(a)
ans =
8.8818e-16
Using a Starting Point
Suppose you do not know two points at which the function values of humps differ in sign. In that case, you can choose a scalar x0 as the starting point for fzero. fzero first searches for an interval around this point on which the function changes sign. If fzero finds such an interval, it proceeds with the algorithm described in the previous section. If no such interval is found, fzero returns NaN.
For example, set the starting point to -0.2, the Display option to Iter, and call fzero:
options = optimset('Display','iter');
a = fzero(@humps,-0.2,options)
Search for an interval around -0.2 containing a sign change:
Func-count a f(a) b f(b) Procedure
1 -0.2 -1.35385 -0.2 -1.35385 initial interval
3 -0.194343 -1.26077 -0.205657 -1.44411 search
5 -0.192 -1.22137 -0.208 -1.4807 search
7 -0.188686 -1.16477 -0.211314 -1.53167 search
9 -0.184 -1.08293 -0.216 -1.60224 search
11 -0.177373 -0.963455 -0.222627 -1.69911 search
13 -0.168 -0.786636 -0.232 -1.83055 search
15 -0.154745 -0.51962 -0.245255 -2.00602 search
17 -0.136 -0.104165 -0.264 -2.23521 search
18 -0.10949 0.572246 -0.264 -2.23521 search
Search for a zero in the interval [-0.10949, -0.264]:
Func-count x f(x) Procedure
18 -0.10949 0.572246 initial
19 -0.140984 -0.219277 interpolation
20 -0.132259 -0.0154224 interpolation
21 -0.131617 3.40729e-05 interpolation
22 -0.131618 -6.79505e-08 interpolation
23 -0.131618 -2.98428e-13 interpolation
24 -0.131618 8.88178e-16 interpolation
25 -0.131618 8.88178e-16 interpolation
Zero found in the interval [-0.10949, -0.264]
a =
-0.1316
The endpoints of the current subinterval at each iteration are listed under the headings a and b, while the corresponding values of humps at the endpoints are listed under f(a) and f(b), respectively.
Note: The endpoints a and b are not listed in any specific order: a can be greater than b or less than b.
For the first nine steps, the sign of humps is negative at both endpoints of the current subinterval, which is shown in the output. At the tenth step, the sign of humps is positive at the endpoint, -0.10949, but negative at the endpoint, -0.264. From this point on, the algorithm continues to narrow down the interval [-0.10949 -0.264], as described in the previous section, until it reaches the value -0.1316.
Parameterizing Functions
Overview
This topic explains how to store or access extra parameters for mathematical functions that you pass to MATLAB® function functions, such as fzero or integral.
MATLAB function functions evaluate mathematical expressions over a range of values. They are called function functions because they are functions that accept a function handle (a pointer to a function) as an input. Each of these functions expects that your objective function has a specific number of input variables. For example, fzero and integral accept handles to functions that have exactly one input variable.
Suppose you want to find the zero of the cubic polynomial x3 + bx + c for different values of the coefficients b and c. Although you could create a function that accepts three input variables (x, b, and c), you cannot pass a function handle that requires all three of those inputs to fzero. However, you can take advantage of properties of anonymous or nested functions to define values for additional inputs.
Parameterizing Using Nested Functions
One approach for defining parameters is to use a nested function—a function completely contained within another function in a program file. For this example, create a file named findzero.m that contains a parent function findzero and a nested function poly:
function y = findzero(b,c,x0)
y = fzero(@poly,x0);
function y = poly(x)
y = x^3 + b*x + c;
end
end
The nested function defines the cubic polynomial with one input variable, x. The parent function accepts the parameters b and c as input values. The reason to nest poly within findzero is that nested functions share the workspace of their parent functions. Therefore, the poly function can access the values of b and c that you pass to findzero.
To find a zero of the polynomial with b = 2 and c = 3.5, using the starting point x0 = 0, you can call findzero from the command line:
x = findzero(2,3.5,0)
x =
-1.0945
Parameterizing Using Anonymous Functions
Another approach for accessing extra parameters is to use an anonymous function. Anonymous functions are functions that you can define in a single command, without creating a separate program file. They can use any variables that are available in the current workspace.
For example, create a handle to an anonymous function that describes the cubic polynomial, and find the zero:
b = 2;
c = 3.5;
cubicpoly = @(x) x^3 + b*x + c;
x = fzero(cubicpoly,0)
x =
-1.0945
Variable cubicpoly is a function handle for an anonymous function that has one input, x. Inputs for anonymous functions appear in parentheses immediately following the @ symbol that creates the function handle. Because b and c are in the workspace when you create cubicpoly, the anonymous function does not require inputs for those coefficients.
You do not need to create an intermediate variable, cubicpoly, for the anonymous function. Instead, you can include the entire definition of the function handle within the call to fzero:
b = 2;
c = 3.5;
x = fzero(@(x) x^3 + b*x + c,0)
x =
-1.0945
You also can use anonymous functions to call more complicated objective functions that you define in a function file. For example, suppose you have a file named cubicpoly.m with this function definition:
function y = cubicpoly(x,b,c)
y = x^3 + b*x + c;
end
At the command line, define b and c, and then call fzero with an anonymous function that invokes cubicpoly:
b = 2;
c = 3.5;
x = fzero(@(x) cubicpoly(x,b,c),0)
x =
-1.0945
Note: To change the values of the parameters, you must create a new anonymous function. For example: