├── .gitignore
├── LICENSE.md
├── README.md
├── docs
├── RankineLab_technical_note.pdf
├── latex_source.zip
└── rankine_cycle_diagrams.svg
├── examples
├── MM
│ └── MM.m
├── R600a
│ └── R600a.m
└── sCO2
│ └── sCO2.m
└── source_code
├── create_data_structure.m
├── create_problem_structures.m
├── evaluate_compressor.m
├── evaluate_exchanger.m
├── evaluate_expander.m
├── evaluate_optimization_problem.m
├── evaluate_rankine_cycle.m
├── export_fig
├── .gitignore
├── Export_fig.prj
├── ImageSelection.class
├── ImageSelection.java
├── LICENSE
├── README.md
├── append_pdfs.m
├── copyfig.m
├── crop_borders.m
├── eps2pdf.m
├── export_fig.m
├── fix_lines.m
├── ghostscript.m
├── hyperlink.m
├── im2gif.m
├── isolate_axes.m
├── pdf2eps.m
├── pdftops.m
├── print2array.m
├── print2eps.m
├── read_write_entire_textfile.m
├── resources
│ └── project
│ │ ├── Extensions.type.Root
│ │ └── DependencyAnalysis.type.Extension
│ │ │ └── ExternalFiles.type.Extension.xml
│ │ ├── Project.xml
│ │ ├── ProjectData.type.Info.xml
│ │ ├── Root.type.Categories
│ │ ├── FileClassCategory.type.Category.xml
│ │ └── FileClassCategory.type.Category
│ │ │ ├── artifact.type.Label.xml
│ │ │ ├── convenience.type.Label.xml
│ │ │ ├── derived.type.Label.xml
│ │ │ ├── design.type.Label.xml
│ │ │ ├── none.type.Label.xml
│ │ │ ├── other.type.Label.xml
│ │ │ └── test.type.Label.xml
│ │ ├── Root.type.Files
│ │ ├── .gitignore.type.File.xml
│ │ ├── ImageSelection.class.type.File.xml
│ │ ├── ImageSelection.java.type.File.xml
│ │ ├── LICENSE.type.File.xml
│ │ ├── README.md.type.File.xml
│ │ ├── append_pdfs.m.type.File.xml
│ │ ├── copyfig.m.type.File.xml
│ │ ├── crop_borders.m.type.File.xml
│ │ ├── eps2pdf.m.type.File.xml
│ │ ├── export_fig.m.type.File.xml
│ │ ├── fix_lines.m.type.File.xml
│ │ ├── ghostscript.m.type.File.xml
│ │ ├── im2gif.m.type.File.xml
│ │ ├── isolate_axes.m.type.File.xml
│ │ ├── pdf2eps.m.type.File.xml
│ │ ├── pdftops.m.type.File.xml
│ │ ├── print2array.m.type.File.xml
│ │ ├── print2eps.m.type.File.xml
│ │ ├── read_write_entire_textfile.m.type.File.xml
│ │ ├── user_string.m.type.File.xml
│ │ └── using_hg2.m.type.File.xml
│ │ ├── Root.type.ProjectPath
│ │ └── a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml
│ │ └── uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml
├── user_string.m
└── using_hg2.m
├── plot_functions
├── create_plots.m
├── plot_TQ_diagram.m
├── plot_Th_diagram.m
├── plot_Ts_diagram.m
└── set_plot_options.m
├── print_solution.m
├── property_functions
├── cluster_func.m
├── liq_line.m
├── prop_calculation.m
├── quality.m
├── sat_line.m
└── vap_line.m
├── save_current_solution.m
├── save_solution.m
└── solve_optimization_problem.m
/.gitignore:
--------------------------------------------------------------------------------
1 | *_results/
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Roberto Agromayor
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RankineLab
2 |
3 | ## Description
4 |
5 | `RankineLab` is a MATLAB tool for the thermodynamic analysis and optimization of Rankine cycles. The code was developed aiming at simplicity and flexibility in terms of cycle configurations and operating conditions. Some of the notable features of the code are listed below:
6 |
7 | - Supports simple and recuperated Rankine cycle architectures.
8 | - Supports a wide range of cycle configurations, including: trilateral, partial-evaporation, saturated, superheated, transcritical, and supecritical cycles.
9 | - Supports a wide range of fluids, such as water, carbon dioxide, refrigerants, hydrocarbons and siloxanes.
10 | - Supports first law (energy) and second law (exergy) cycle analyses.
11 | - Uses the equations of state of the [CoolProp](http://www.coolprop.org/) or [REFPROP](https://pages.nist.gov/REFPROP-docs/) fluid libraries to compute the thermodynamic properties of the fluids.
12 | - Uses the gradient-based algorithms of the [MATLAB Optimization Toolbox](https://se.mathworks.com/products/optimization.html) to find the optimal cycle configuration in a systematic way. The usual execution time for one cycle optimization is less than 10 seconds on a single core.
13 |
14 |
15 |
16 |
17 |
18 | ## Installation
19 |
20 | In order to use `RankineLab`, you need a MATLAB installation and the MATLAB Optimization Toolbox. In addition you need to install CoolProp and interface it with MATLAB through Python. This may sound complicated, but it is not!
21 |
22 | Check the step-by-step instructions below to learn how to interface MATLAB with CoolProp in a Windows operating system. The installation for Linux or Mac operating systems would be similar.
23 |
24 | #### Step 1 - Download and install Miniconda
25 |
26 | Download the [Miniconda](https://docs.conda.io/en/latest/miniconda.html) environment management system and follow the installation instructions.
27 |
28 | #### Step 2 - Create a virtual environment and install CoolProp
29 |
30 | Open a Miniconda terminal (look for "Anaconda Prompt" or "Miniconda3"). Once the terminal is open, type the following command to create a new virtual environment named `coolprop_env`:
31 |
32 | ```shell
33 | conda create --name coolprop_env python=3.8
34 | ```
35 |
36 | Don't worry if you are not familiar with the command window or with virtual environments, you only have to type two more commands before the installation is complete. Now that the environment is created, you can activate it. Just use the following command:
37 |
38 | ```shell
39 | conda activate coolprop_env
40 | ```
41 |
42 | Finally, type the following command to install CoolProp:
43 |
44 | ```shell
45 | conda install CoolProp --channel conda-forge
46 | ```
47 |
48 | That's it! Note that it was necessary to tell Miniconda that it should look for Coolprop in the `conda-forge` channel.
49 |
50 | #### Step 3 - Interface MATLAB and Coolprop
51 |
52 | Open MATLAB (or close and open it if it was already open) and type the following command to let MATLAB know where is the Python executable (python.exe) of the virtual environment that you have just created:
53 |
54 | ```matlab
55 | pyversion C:\Users\rober\.conda\envs\coolprop_env\python.exe
56 | ```
57 |
58 | Note that, in my case, the executable was located at `C:\Users\rober\.conda\envs\coolprop_env\`. You should replace this part with the correct path in your computer.
59 |
60 | Good! You have installed CoolProp and interfaced it with MATLAB. Let's do a simple test to check if the installation was successful. We are going to use CoolProp to compute the saturation temperature of water at atmospheric pressure. Just type the following command in MATLAB:
61 |
62 | ```matlab
63 | py.CoolProp.CoolProp.PropsSI('T','P',101325,'Q',0,'Water')
64 | ```
65 |
66 |
67 | If it does not throw and error and returns 373.1243 K, the installation was successful.
68 |
69 | ## Getting started
70 |
71 | The best way to learn how to use `RankineLab` is to open one of the [examples](examples/) and start playing around with the different parameters and settings. The examples have plenty of comments to guide the users and help them understand how the code works. You can use the example scripts as a template to start your own projects.
72 |
73 | ## Mathematical background
74 |
75 | Check out the [technical note](./docs/RankineLab_technical_note.pdf) if you want to learn more about the formulation of the optimization problem and the thermodynamic modeling behind `RankOpt`.
76 |
77 | ## License
78 |
79 | `RankineLab` is licensed under the terms of the MIT license. See the [license file](LICENSE.md) for more information.
80 |
81 | ## Contact information
82 |
83 | `RankineLab` was developed by [Roberto Agromayor](https://www.ntnu.edu/employees/roberto.agromayor) and of [Lars O. Nord](https://www.ntnu.edu/employees/lars.nord) at the [Norwegian University of Science and Technology (NTNU)](https://www.ntnu.no/). Drop us an email to [roberto.agromayor@ntnu.no](mailto:roberto.agromayor@ntnu.no) if you have questions about the code or you have a bug to report!
84 |
--------------------------------------------------------------------------------
/docs/RankineLab_technical_note.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turbo-sim/RankineLab/f09b7ee6ddc17f0987951fc74d79dc2c02faf829/docs/RankineLab_technical_note.pdf
--------------------------------------------------------------------------------
/docs/latex_source.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turbo-sim/RankineLab/f09b7ee6ddc17f0987951fc74d79dc2c02faf829/docs/latex_source.zip
--------------------------------------------------------------------------------
/examples/MM/MM.m:
--------------------------------------------------------------------------------
1 | %% RankineLab - A MATLAB program to optimize Rankine cycles
2 | % Authors: Roberto Agromayor
3 | % Date: Spring 2021
4 |
5 |
6 | %% Initialize the program
7 | % Clear all variables and close all figures
8 | clear all
9 | close all
10 | clc
11 |
12 | % Add the path to the 'source_code' directory
13 | % The function genpath() is very convenient
14 | addpath(genpath('../../source_code'))
15 |
16 | % Set a project name (mfilename corresponds to the script name)
17 | project_name = mfilename;
18 |
19 | % Create a directory to store the figures and results
20 | results_path = fullfile(pwd, [project_name, '_results']);
21 | if exist(results_path, 'dir') ~= 7 % 7 is a MATLAB's convention
22 | mkdir(results_path)
23 | else
24 | rmdir(results_path, 's')
25 | mkdir(results_path)
26 | end
27 |
28 |
29 | %% Define the thermodynamic specifications and cycle parameters
30 | % Ambient state
31 | p_0 = 101325; % Ambient pressure
32 | T_0 = 20+273.15; % Ambient temperature
33 |
34 | % Define the working fluids
35 | heating_fluid = 'HEOS::Air';
36 | working_fluid = 'HEOS::MM';
37 | cooling_fluid = 'HEOS::Water';
38 |
39 | % Some guidance to select the fluid name and EoS
40 | %{
41 |
42 | You can set the back-end used to compute the thermodynamic properties by
43 | precedding the fluid name by 'HEOS::' (for the Coolprop back-end) or by
44 | 'REFPROP::' (for the REFPROP backend).
45 |
46 | You can check the list of the CoolProp back-end fluid names here:
47 | http://www.coolprop.org/fluid_properties/PurePseudoPure.html
48 |
49 | Note that the fluid names for REFPROP may be different
50 |
51 | The equations of state may fail for some thermodynamic states and break
52 | down the optimization progress (oh, the horror...)
53 |
54 | This is depedent on the fluid and the EoS back-end (REFPROP/CoolProp)
55 |
56 | My recommendation is to try the CoolProp back-end first
57 | 1) CoolProp EoS are (much) faster, but can fail sometimes
58 | 2) REFPROP EoS are slower, but they are also a bit more robust
59 |
60 | The worst kind of error that you can get while executing the code is
61 | that the equations of state fail.
62 |
63 | There is not much to do about it when it happens because it depends on the
64 | CoolProp/REFPROP libraries.
65 |
66 | If you encounter this problem you can try to start the optimization from a
67 | different initial guess, change the bounds/constraints of the optimization
68 | or, as a last measure, change the EoS back-to REFPROP.
69 |
70 | If all of these fail, you are out of luck...
71 |
72 | %}
73 |
74 | % Define the thermodynamic specifications of the heat source
75 | m_h = 1.00; % Heat source mass flow rate (kg/s). This variable "scales-up" the problem
76 | T_1 = 300+273.15; % Heat source inlet temperature (K)
77 | p_1 = p_0; % Heat source inlet pressure (Pa)
78 | p_3 = p_0; % Heat source outlet pressure (Pa)
79 | T_3min = 120+273.15; % Minimum temperature at the outlet of the heat source (K)
80 | T_3max = T_1; % Maximum temperature at the outlet of the heat source (K)
81 |
82 | % Define the thermodynamic specifications of the heat sink
83 | T_10 = T_0; % Heat sink inlet temperature (K)
84 | p_10 = p_0; % Heat sink inlet pressure (Pa)
85 | p_12 = p_0; % Heat sink outlet pressure (Pa)
86 | T_12min = T_0+10; % Minimum temperature at the outlet of the heat sink (K)
87 | T_12max = T_0+20; % Maximum temperature at the outlet of the heat sink (K)
88 |
89 | % Define pressure drops in the heat exchangers (% of the inlet pressure)
90 | dp_h_evap = 0.02; % Pressure drop in the heating fluid side of the evaporator (relative with respect to inlet)
91 | dp_c_evap = 0.02; % Pressure drop in the working fluid side of the evaporator (relative with respect to inlet)
92 | dp_h_cond = 0.02; % Pressure drop in the working fluid side of the condenser (relative with respect to inlet)
93 | dp_c_cond = 0.02; % Pressure drop in the cooling fluid side of the condenser (relative with respect to inlet)
94 | dp_h_rec = 0.02; % Pressure drop in the hot side of the recuperator (relative with respect to inlet)
95 | dp_c_rec = 0.02; % Pressure drop in the cold side of the recuperator (relative with respect to inlet)
96 |
97 | % Define the number of discretizations of the heat exchangers
98 | % More discretizations: more accurate pinch point and more execution time
99 | N_evap = 50; % Choose an integer
100 | N_cond = 50; % Choose an integer
101 | N_rec = 50; % Choose an integer
102 |
103 | % Define the efficiency of the pumps
104 | eta_pump_h = 0.80; % Isentropic efficiency of the heat source pump
105 | eta_pump_f = 0.80; % Isentropic efficiency of the working fluid pump
106 | eta_pump_c = 0.80; % Isentropic efficiency of the heat sink pump
107 |
108 | % Define the efficiency of the expander
109 | eta_expander = 0.90; % Efficiency of the expander
110 |
111 | % Turbomachinery efficiency definition
112 | pump_efficiency_definition = 'isentropic'; % Definition of the pump efficiency: 'isentropic' or 'polytropic'
113 | expander_efficiency_definition = 'isentropic'; % Definition of the expander efficiency: 'isentropic' or 'polytropic'
114 |
115 | % More details about the efficiency definition
116 | %{
117 |
118 | If you set efficiency_definition='isentropic' the efficiency of the
119 | working fluid pump and expander are defined as:
120 |
121 | eta_pump = (h_out_s-h_in)/(h_out-h_in)
122 | eta_expander = (h_in-h_out)/(h_in-h_out_s)
123 |
124 | and the turbomachinery computations only involve the inlet and exit states
125 |
126 | If you set efficiency_definition='polytropic' the efficiency of the working
127 | fluid pump and expander are defined as:
128 |
129 | eta_pump = dh_s/dh = 1/d*dp/dh
130 | eta_expander = dh/dh_s = d*dh/dp
131 |
132 | and the turbomachinery computations are performed by solving the previous
133 | ordinary differential equations (ODE) along the compression or expansion
134 |
135 | %}
136 |
137 |
138 | %% Define extra fluid parameters
139 | % Used to scale degrees of freedom (no need to do changes in most cases)
140 | % Define the critical properties
141 | p_crit = prop_calculation('P_CRITICAL',working_fluid); % Critical pressure
142 | T_crit = prop_calculation('T_CRITICAL',working_fluid); % Critical temperature
143 | % p_crit = [];
144 | % T_crit = [];
145 |
146 | % Define the triple properties (only pure substances)
147 | p_trip = prop_calculation('P_TRIPLE',working_fluid); % Triple pressure
148 | T_trip = prop_calculation('T_TRIPLE',working_fluid); % Triple temperature
149 | % p_trip = [];
150 | % T_trip = [];
151 |
152 | % Define the saturation pressure and enthalpy at ambient temperature
153 | % If the ambient temperature is higher than the critical temperature use
154 | % the critical pressure and enthalpy instead
155 | if T_0 < T_crit
156 | p_sat0 = prop_calculation('P','T',T_0,'Q',0,working_fluid);
157 | h_sat0 = prop_calculation('H','T',T_0,'Q',0,working_fluid);
158 | else
159 | p_sat0 = p_crit;
160 | h_sat0 = prop_calculation('H','T',T_crit,'P',p_crit,working_fluid);
161 | end
162 |
163 | % Define the pressure and temperature limits
164 | p_min = 1.01*p_trip; % Minimum pressure
165 | p_max = 5.00*p_crit; % Maximum pressure
166 | T_min = T_0; % Maximum temperature
167 | T_max = 1.50*T_crit; % Maximum temperature
168 |
169 | % Define the enthalpy limits
170 | h_min = h_sat0;
171 | h_max = prop_calculation('H','T',T_1,'P',1e-3,working_fluid);
172 |
173 |
174 | %% Define the independent variables and bounds
175 | % x1 = Heat source exit temperature
176 | x1 = 0.25;
177 | x1_min = 0.00;
178 | x1_max = 1.00;
179 |
180 | % x2 = Heat sink exit temperature
181 | x2 = 0.25;
182 | x2_min = 0.00;
183 | x2_max = 1.00;
184 |
185 | % x3 = Pump inlet pressure (subcritical)
186 | x3 = (1.5*p_sat0-p_min)/(p_max-p_min);
187 | x3_min = 0.00;
188 | x3_max = 1.00;
189 |
190 | % x4 = Pump inlet enthalpy
191 | x4 = 0.05;
192 | x4_min = 0.00;
193 | x4_max = 1.00;
194 |
195 | % x5 = Expander inlet pressure
196 | x5 = (1.5*p_crit-p_min)/(p_max-p_min);
197 | x5_min = 0.00;
198 | x5_max = 1.00;
199 |
200 | % x6 = Expander inlet enthalpy
201 | x6 = 0.80;
202 | x6_min = 0.00;
203 | x6_max = 1.00;
204 |
205 | % x7 = Recuperator effectiveness (set to zero for no recuperator)
206 | x7 = 0.25;
207 | x7_min = 0.00;
208 | x7_max = 1.00;
209 |
210 | % Organize the information in vectors
211 | lb_cycle = [x1_min, x2_min, x3_min, x4_min, x5_min, x6_min, x7_min]';
212 | ub_cycle = [x1_max, x2_max, x3_max, x4_max, x5_max, x6_max, x7_max]';
213 | x0_cycle = [x1, x2, x3, x4, x5, x6, x7]';
214 |
215 | % Some guidelines for the degrees of freedom
216 | %{
217 |
218 | Play around with x0_cycle to find a good initial guess.
219 |
220 | Mathematical definition of the degrees of freedom
221 | x1 = (T_3 - T_3min) / (T_3max - T_3min)
222 | x2 = (T_12 - T_12min) / (T_12max - T_12min)
223 | x3 = (p_4 - p_min) / (p_max - p_min)
224 | x4 = (h_4 - h_min) / (h_max - h_min)
225 | x5 = (p_7 - p_min) / (p_max - p_min)
226 | x6 = (h_7 - h_min) / (h_max - h_min)
227 | x7 = (h6 - h5) / (h(p6,T8) - h5)
228 |
229 | If you want a cycle configuration with no recuperator you have to:
230 | 1) Set the recuperator effectiveness equal to zero:
231 | x7 = x7_min = x7_max = 0.00
232 | 2) Set the pressure drops in the recuperator equal to zero:
233 | dp_h_rec = dp_c_rec = 0.00
234 | 3) Do not apply a constraint for the recuperator pinch point dT:
235 | constraints.dT_rec.apply = 'no'
236 |
237 | How to give start values when you use the code for the first time?
238 | x1 usually takes low values (maximum exploitation of the heat source)
239 | x2 usually takes low values (small temperature jump in the heat sink)
240 | x3 usually takes low values (low pressure at the exit of the condenser)
241 | x4 usually takes low values (low enthalpy at the exit of the condenser)
242 | x5x_crit for transcritical cycles
243 | x6 usually takes high values (high enthalpy at the inlet of the evap.)
244 | x7=0 corresponds to no recuperation and x=1 to ideal recuperation
245 |
246 | Note: Low means close to zero and high means close to one
247 |
248 | %}
249 |
250 |
251 | %% Define the constraints
252 | % Instructions:
253 | % 1. Specify the minimum and maximum values
254 | % 2. Specify whether to apply the constraint or not
255 | % 3. Use [brackets] to ignore the constraint value
256 |
257 | % Minimum temperature difference in the evaporator (pinch point)
258 | constraints.dT_evap.min = 10;
259 | constraints.dT_evap.apply = 'yes';
260 |
261 | % Minimum temperature difference in the condenser (pinch point)
262 | constraints.dT_cond.min = 10;
263 | constraints.dT_cond.apply = 'yes';
264 |
265 | % Minimum temperature difference in the recuperator (pinch point)
266 | constraints.dT_rec.min = 10;
267 | constraints.dT_rec.apply = 'yes';
268 |
269 | % Minimum vapor quality along the expander
270 | constraints.quality.min = 1.00;
271 | constraints.quality.apply = 'yes';
272 |
273 | % Degree of subcooling at the inlet of the pump
274 | constraints.dT_subcooling.min = 1;
275 | constraints.dT_subcooling.max = [];
276 | constraints.dT_subcooling.apply = 'yes';
277 |
278 | % Degree of superheating at inlet of the expander (subcritical cycles)
279 | constraints.dT_superheating.min = 5;
280 | constraints.dT_superheating.max = [];
281 | constraints.dT_superheating.apply = 'no';
282 |
283 | % Maximum cycle pressure
284 | constraints.pressure.min = [];
285 | constraints.pressure.max = [];
286 | constraints.pressure.apply = 'no';
287 |
288 |
289 | %% Define optimization algorithm settings
290 | % Set optimization algorithm
291 | % 'spq' is my favourite because it converges reliably and respects bounds
292 | % 'active-set' is a bit more aggressive and does not always respect the
293 | % bounds. It is faster, but less reliable, than 'sqp'.
294 | % 'interior-point' also works, but it requires more iterations
295 | algorithm = 'sqp';
296 |
297 | % Compute the problem gradients in parallel or not
298 | use_parallel = false; % true or false
299 |
300 | % Define termination criteria (no need to change in most cases)
301 | max_iterations = 1000;
302 | max_function_evals = 10000;
303 | step_tolerance = 1e-08;
304 | function_tolerance = 1e-05;
305 | constraint_tolerance = 1e-05;
306 | optimality_tolerance = 1e-05;
307 |
308 | % Description of the possible outputs of the optimization function
309 | %{
310 |
311 | 'interior-point', 'active-set', and 'sqp' algorithms
312 | Exitflag = 1 -> Success. First-order optimality measure was less than options and constraints are not violated.
313 | Exitflag = 2 -> Success. Step size was less than options and constraints are not violated.
314 | Exitflag = 0 -> Unsuccess. Number of iterations or function evaluations exceeded option
315 | Exitflag = -1 -> Unsuccess. Solver stopped by an output function
316 | Exitflag = -2 -> Unsuccess. No feasible point was found
317 |
318 | Only active set algorithm
319 | Exitflag = 4 -> Success. Magnitude of the search direction was less than 2*options.StepTolerance and maximum constraint violation was less than options.ConstraintTolerance.
320 | Exitflag = 5 -> Success. Magnitude of directional derivative in search direction was less than 2*options.OptimalityTolerance and maximum constraint violation was less than options.ConstraintTolerance.
321 |
322 | %}
323 |
324 |
325 | %% Choose what figures should be plotted
326 | choose_plots = struct('diagram_TQ', 'yes', ... % Temperature - heat duty diagram
327 | 'diagram_Ts', 'yes', ... % Temperature - entropy diagram of the cycle
328 | 'diagram_Th', 'yes', ... % Temperature - enthalpy diagram of the cycle
329 | 'save', 0); % Choose whether to save the figures or not
330 |
331 | % Description of the saving options
332 | %{
333 |
334 | save=0 does not save the figures
335 | save=1 saves the figure in vector format using the default MATLAB export function (faster)
336 | save=2 saves the figure in vector using the export_fig library (requires ghostscript)
337 |
338 | In order to use save=2 it is necessary to install 'ghoscript'
339 | https://github.com/altmany/export_fig
340 | http://www.ghostscript.com
341 | http://xpdfreader.com
342 |
343 | %}
344 |
345 |
346 | %% Store the parameters defined up to this point into data structures
347 | % The script 'create_problem_structures' located in source_code folder
348 | % 1) 'fixed_parameters' stores the cycle specifications
349 | % 2) 'optimization_problem' stores the optimization problem settings
350 | create_problem_structures
351 |
352 | % These data structures are created in a different script to keep the
353 | % number of lines of this script to a minimum
354 |
355 | % Be tidy and clear the worskpace now that we stored everything
356 | clearvars -except optimization_problem fixed_parameters project_name results_path
357 |
358 |
359 | %% Load a previous solution as initial guess
360 | % % Uncomment these lines to use a previous solution as initial guess
361 | % load(fullfile(fixed_parameters.results_path,'cycle_data.mat'))
362 | % optimization_problem.x0 = cycle_data.optimization.x;
363 |
364 |
365 | %% Plot the initial solution
366 | filename_suffix = 'initial';
367 | cycle_data = create_plots(optimization_problem.x0,fixed_parameters,filename_suffix);
368 | print_solution(cycle_data)
369 |
370 |
371 | %% Solve the optimization problem
372 | [cycle_data,x_opt,f_opt,exitflag,output,lambda] = solve_optimization_problem(fixed_parameters,optimization_problem);
373 | save_solution(cycle_data, project_name, results_path)
374 |
375 | %% Plot the optimal solution
376 | filename_suffix = 'optimal';
377 | create_plots(x_opt,fixed_parameters,filename_suffix);
378 | print_solution(cycle_data)
379 |
380 |
381 |
382 |
--------------------------------------------------------------------------------
/examples/R600a/R600a.m:
--------------------------------------------------------------------------------
1 | %% RankineLab - A MATLAB program to optimize Rankine cycles
2 | % Authors: Roberto Agromayor
3 | % Date: Spring 2021
4 |
5 |
6 | %% Initialize the program
7 | % Clear all variables and close all figures
8 | clear all
9 | close all
10 | clc
11 |
12 | % Add the path to the 'source_code' directory
13 | % The function genpath() is very convenient
14 | addpath(genpath('../../source_code'))
15 |
16 | % Set a project name (mfilename corresponds to the script name)
17 | project_name = mfilename;
18 |
19 | % Create a directory to store the figures and results
20 | results_path = fullfile(pwd, [project_name, '_results']);
21 | if exist(results_path, 'dir') ~= 7 % 7 is a MATLAB's convention
22 | mkdir(results_path)
23 | else
24 | rmdir(results_path, 's')
25 | mkdir(results_path)
26 | end
27 |
28 |
29 | %% Define the thermodynamic specifications and cycle parameters
30 | % Ambient state
31 | p_0 = 101325; % Ambient pressure
32 | T_0 = 15+273.15; % Ambient temperature
33 |
34 | % Define the working fluids
35 | heating_fluid = 'HEOS::Water';
36 | working_fluid = 'HEOS::Isobutane';
37 | cooling_fluid = 'HEOS::Water';
38 |
39 | % Some guidance to select the fluid name and EoS
40 | %{
41 |
42 | You can set the back-end used to compute the thermodynamic properties by
43 | precedding the fluid name by 'HEOS::' (for the Coolprop back-end) or by
44 | 'REFPROP::' (for the REFPROP backend).
45 |
46 | You can check the list of the CoolProp back-end fluid names here:
47 | http://www.coolprop.org/fluid_properties/PurePseudoPure.html
48 |
49 | Note that the fluid names for REFPROP may be different
50 |
51 | The equations of state may fail for some thermodynamic states and break
52 | down the optimization progress (oh, the horror...)
53 |
54 | This is depedent on the fluid and the EoS back-end (REFPROP/CoolProp)
55 |
56 | My recommendation is to try the CoolProp back-end first
57 | 1) CoolProp EoS are (much) faster, but can fail sometimes
58 | 2) REFPROP EoS are slower, but they are also a bit more robust
59 |
60 | The worst kind of error that you can get while executing the code is
61 | that the equations of state fail.
62 |
63 | There is not much to do about it when it happens because it depends on the
64 | CoolProp/REFPROP libraries.
65 |
66 | If you encounter this problem you can try to start the optimization from a
67 | different initial guess, change the bounds/constraints of the optimization
68 | or, as a last measure, change the EoS back-to REFPROP.
69 |
70 | If all of these fail, you are out of luck...
71 |
72 | %}
73 |
74 | % Define the thermodynamic specifications of the heat source
75 | m_h = 1.00; % Heat source mass flow rate (kg/s). This variable "scales-up" the problem
76 | T_1 = 120+273.15; % Heat source inlet temperature (K)
77 | p_1 = 3*p_0; % Heat source inlet pressure (Pa)
78 | p_3 = 3*p_0; % Heat source outlet pressure (Pa)
79 | T_3min = 75+273.15; % Minimum temperature at the outlet of the heat source (K)
80 | T_3max = T_1; % Maximum temperature at the outlet of the heat source (K)
81 |
82 | % Define the thermodynamic specifications of the heat sink
83 | T_10 = 10+273.15; % Heat sink inlet temperature (K)
84 | p_10 = p_0; % Heat sink inlet pressure (Pa)
85 | p_12 = p_0; % Heat sink outlet pressure (Pa)
86 | T_12min = 10+273.15+10; % Minimum temperature at the outlet of the heat sink (K)
87 | T_12max = T_0+20; % Maximum temperature at the outlet of the heat sink (K)
88 |
89 | % Define pressure drops in the heat exchangers (% of the inlet pressure)
90 | dp_h_evap = 0.02; % Pressure drop in the heating fluid side of the evaporator (relative with respect to inlet)
91 | dp_c_evap = 0.02; % Pressure drop in the working fluid side of the evaporator (relative with respect to inlet)
92 | dp_h_cond = 0.02; % Pressure drop in the working fluid side of the condenser (relative with respect to inlet)
93 | dp_c_cond = 0.02; % Pressure drop in the cooling fluid side of the condenser (relative with respect to inlet)
94 | dp_h_rec = 0.00; % Pressure drop in the hot side of the recuperator (relative with respect to inlet)
95 | dp_c_rec = 0.00; % Pressure drop in the cold side of the recuperator (relative with respect to inlet)
96 |
97 | % Define the number of discretizations of the heat exchangers
98 | % More discretizations: more accurate pinch point and more execution time
99 | N_evap = 50; % Choose an integer
100 | N_cond = 50; % Choose an integer
101 | N_rec = 50; % Choose an integer
102 |
103 | % Define the efficiency of the pumps
104 | eta_pump_h = 0.70; % Isentropic efficiency of the heat source pump
105 | eta_pump_f = 0.70; % Isentropic efficiency of the working fluid pump
106 | eta_pump_c = 0.70; % Isentropic efficiency of the heat sink pump
107 |
108 | % Define the efficiency of the expander
109 | eta_expander = 0.70; % Efficiency of the expander
110 |
111 | % Turbomachinery efficiency definition
112 | pump_efficiency_definition = 'isentropic'; % Definition of the pump efficiency: 'isentropic' or 'polytropic'
113 | expander_efficiency_definition = 'isentropic'; % Definition of the expander efficiency: 'isentropic' or 'polytropic'
114 |
115 | % More details about the efficiency definition
116 | %{
117 |
118 | If you set efficiency_definition='isentropic' the efficiency of the
119 | working fluid pump and expander are defined as:
120 |
121 | eta_pump = (h_out_s-h_in)/(h_out-h_in)
122 | eta_expander = (h_in-h_out)/(h_in-h_out_s)
123 |
124 | and the turbomachinery computations only involve the inlet and exit states
125 |
126 | If you set efficiency_definition='polytropic' the efficiency of the working
127 | fluid pump and expander are defined as:
128 |
129 | eta_pump = dh_s/dh = 1/d*dp/dh
130 | eta_expander = dh/dh_s = d*dh/dp
131 |
132 | and the turbomachinery computations are performed by solving the previous
133 | ordinary differential equations (ODE) along the compression or expansion
134 |
135 | %}
136 |
137 |
138 | %% Define extra fluid parameters
139 | % Used to scale degrees of freedom (no need to do changes in most cases)
140 | % Define the critical properties
141 | p_crit = prop_calculation('P_CRITICAL',working_fluid); % Critical pressure
142 | T_crit = prop_calculation('T_CRITICAL',working_fluid); % Critical temperature
143 | % p_crit = [];
144 | % T_crit = [];
145 |
146 | % Define the triple properties (only pure substances)
147 | p_trip = prop_calculation('P_TRIPLE',working_fluid); % Triple pressure
148 | T_trip = prop_calculation('T_TRIPLE',working_fluid); % Triple temperature
149 | % p_trip = [];
150 | % T_trip = [];
151 |
152 | % Define the saturation pressure and enthalpy at ambient temperature
153 | % If the ambient temperature is higher than the critical temperature use
154 | % the critical pressure and enthalpy instead
155 | if T_0 < T_crit
156 | p_sat0 = prop_calculation('P','T',T_0,'Q',0,working_fluid);
157 | h_sat0 = prop_calculation('H','T',T_0,'Q',0,working_fluid);
158 | else
159 | p_sat0 = p_crit;
160 | h_sat0 = prop_calculation('H','T',T_crit,'P',p_crit,working_fluid);
161 | end
162 |
163 | % Define the pressure and temperature limits
164 | p_min = 1.01*p_trip; % Minimum pressure
165 | p_max = 3.00*p_crit; % Maximum pressure
166 | T_min = T_0; % Maximum temperature
167 | T_max = 1.50*T_crit; % Maximum temperature
168 |
169 | % Define the enthalpy limits
170 | h_min = h_sat0;
171 | h_max = prop_calculation('H','T',T_1,'P',1e-3,working_fluid);
172 |
173 |
174 | %% Define the independent variables and bounds
175 | % x1 = Heat source exit temperature
176 | x1 = 0.25;
177 | x1_min = 0.00;
178 | x1_max = 1.00;
179 |
180 | % x2 = Heat sink exit temperature
181 | x2 = 0.25;
182 | x2_min = 0.00;
183 | x2_max = 1.00;
184 |
185 | % x3 = Pump inlet pressure (subcritical)
186 | x3 = (1.5*p_sat0-p_min)/(p_max-p_min);
187 | x3_min = 0.00;
188 | x3_max = 1.00;
189 |
190 | % x4 = Pump inlet enthalpy
191 | x4 = 0.05;
192 | x4_min = 0.00;
193 | x4_max = 1.00;
194 |
195 | % x5 = Expander inlet pressure
196 | x5 = (0.50*p_crit-p_min)/(p_max-p_min);
197 | x5_min = 0.00;
198 | x5_max = 1.00;
199 |
200 | % x6 = Expander inlet enthalpy
201 | x6 = 0.80;
202 | x6_min = 0.00;
203 | x6_max = 1.00;
204 |
205 | % x7 = Recuperator effectiveness (set to zero for no recuperator)
206 | x7 = 0.00;
207 | x7_min = 0.00;
208 | x7_max = 0.00;
209 |
210 | % Organize the information in vectors
211 | lb_cycle = [x1_min, x2_min, x3_min, x4_min, x5_min, x6_min, x7_min]';
212 | ub_cycle = [x1_max, x2_max, x3_max, x4_max, x5_max, x6_max, x7_max]';
213 | x0_cycle = [x1, x2, x3, x4, x5, x6, x7]';
214 |
215 | % Some guidelines for the degrees of freedom
216 | %{
217 |
218 | Play around with x0_cycle to find a good initial guess.
219 |
220 | Mathematical definition of the degrees of freedom
221 | x1 = (T_3 - T_3min) / (T_3max - T_3min)
222 | x2 = (T_12 - T_12min) / (T_12max - T_12min)
223 | x3 = (p_4 - p_min) / (p_max - p_min)
224 | x4 = (h_4 - h_min) / (h_max - h_min)
225 | x5 = (p_7 - p_min) / (p_max - p_min)
226 | x6 = (h_7 - h_min) / (h_max - h_min)
227 | x7 = (h6 - h5) / (h(p6,T8) - h5)
228 |
229 | If you want a cycle configuration with no recuperator you have to:
230 | 1) Set the recuperator effectiveness equal to zero:
231 | x7 = x7_min = x7_max = 0.00
232 | 2) Set the pressure drops in the recuperator equal to zero:
233 | dp_h_rec = dp_c_rec = 0.00
234 | 3) Do not apply a constraint for the recuperator pinch point dT:
235 | constraints.dT_rec.apply = 'no'
236 |
237 | How to give start values when you use the code for the first time?
238 | x1 usually takes low values (maximum exploitation of the heat source)
239 | x2 usually takes low values (small temperature jump in the heat sink)
240 | x3 usually takes low values (low pressure at the exit of the condenser)
241 | x4 usually takes low values (low enthalpy at the exit of the condenser)
242 | x5x_crit for transcritical cycles
243 | x6 usually takes high values (high enthalpy at the inlet of the evap.)
244 | x7=0 corresponds to no recuperation and x=1 to ideal recuperation
245 |
246 | Note: Low means close to zero and high means close to one
247 |
248 | %}
249 |
250 |
251 | %% Define the constraints
252 | % Instructions:
253 | % 1. Specify the minimum and maximum values
254 | % 2. Specify whether to apply the constraint or not
255 | % 3. Use [brackets] to ignore the constraint value
256 |
257 | % Minimum temperature difference in the evaporator (pinch point)
258 | constraints.dT_evap.min = 10;
259 | constraints.dT_evap.apply = 'yes';
260 |
261 | % Minimum temperature difference in the condenser (pinch point)
262 | constraints.dT_cond.min = 10;
263 | constraints.dT_cond.apply = 'yes';
264 |
265 | % Minimum temperature difference in the recuperator (pinch point)
266 | constraints.dT_rec.min = 10;
267 | constraints.dT_rec.apply = 'no';
268 |
269 | % Minimum vapor quality along the expander
270 | constraints.quality.min = 1.00;
271 | constraints.quality.apply = 'yes';
272 |
273 | % Degree of subcooling at the inlet of the pump
274 | constraints.dT_subcooling.min = 1;
275 | constraints.dT_subcooling.max = [];
276 | constraints.dT_subcooling.apply = 'yes';
277 |
278 | % Degree of superheating at inlet of the expander (subcritical cycles)
279 | constraints.dT_superheating.min = 5;
280 | constraints.dT_superheating.max = [];
281 | constraints.dT_superheating.apply = 'yes';
282 |
283 | % Maximum cycle pressure
284 | constraints.pressure.min = 1.5e5;
285 | constraints.pressure.max = 15e5;
286 | constraints.pressure.apply = 'yes';
287 |
288 |
289 | %% Define optimization algorithm settings
290 | % Set optimization algorithm
291 | % 'spq' is my favourite because it converges reliably and respects bounds
292 | % 'active-set' is a bit more aggressive and does not always respect the
293 | % bounds. It is faster, but less reliable, than 'sqp'.
294 | % 'interior-point' also works, but it requires more iterations
295 | algorithm = 'sqp';
296 |
297 | % Compute the problem gradients in parallel or not
298 | use_parallel = false; % true or false
299 |
300 | % Define termination criteria (no need to change in most cases)
301 | max_iterations = 1000;
302 | max_function_evals = 10000;
303 | step_tolerance = 1e-08;
304 | function_tolerance = 1e-05;
305 | constraint_tolerance = 1e-05;
306 | optimality_tolerance = 1e-05;
307 |
308 | % Description of the possible outputs of the optimization function
309 | %{
310 |
311 | 'interior-point', 'active-set', and 'sqp' algorithms
312 | Exitflag = 1 -> Success. First-order optimality measure was less than options and constraints are not violated.
313 | Exitflag = 2 -> Success. Step size was less than options and constraints are not violated.
314 | Exitflag = 0 -> Unsuccess. Number of iterations or function evaluations exceeded option
315 | Exitflag = -1 -> Unsuccess. Solver stopped by an output function
316 | Exitflag = -2 -> Unsuccess. No feasible point was found
317 |
318 | Only active set algorithm
319 | Exitflag = 4 -> Success. Magnitude of the search direction was less than 2*options.StepTolerance and maximum constraint violation was less than options.ConstraintTolerance.
320 | Exitflag = 5 -> Success. Magnitude of directional derivative in search direction was less than 2*options.OptimalityTolerance and maximum constraint violation was less than options.ConstraintTolerance.
321 |
322 | %}
323 |
324 |
325 | %% Choose what figures should be plotted
326 | choose_plots = struct('diagram_TQ', 'yes', ... % Temperature - heat duty diagram
327 | 'diagram_Ts', 'yes', ... % Temperature - entropy diagram of the cycle
328 | 'diagram_Th', 'yes', ... % Temperature - enthalpy diagram of the cycle
329 | 'save', 0); % Choose whether to save the figures or not
330 |
331 | % Description of the saving options
332 | %{
333 |
334 | save=0 does not save the figures
335 | save=1 saves the figure in vector format using the default MATLAB export function (faster)
336 | save=2 saves the figure in vector using the export_fig library (requires ghostscript)
337 |
338 | In order to use save=2 it is necessary to install 'ghoscript'
339 | https://github.com/altmany/export_fig
340 | http://www.ghostscript.com
341 | http://xpdfreader.com
342 |
343 | %}
344 |
345 |
346 | %% Store the parameters defined up to this point into data structures
347 | % The script 'create_problem_structures' located in source_code folder
348 | % 1) 'fixed_parameters' stores the cycle specifications
349 | % 2) 'optimization_problem' stores the optimization problem settings
350 | create_problem_structures
351 |
352 | % These data structures are created in a different script to keep the
353 | % number of lines of this script to a minimum
354 |
355 | % Be tidy and clear the worskpace now that we stored everything
356 | clearvars -except optimization_problem fixed_parameters project_name results_path
357 |
358 |
359 | %% Load a previous solution as initial guess
360 | % % Uncomment these lines to use a previous solution as initial guess
361 | % load(fullfile(fixed_parameters.results_path,'cycle_data.mat'))
362 | % optimization_problem.x0 = cycle_data.optimization.x;
363 |
364 |
365 | %% Plot the initial solution
366 | filename_suffix = 'initial';
367 | cycle_data = create_plots(optimization_problem.x0,fixed_parameters,filename_suffix);
368 | print_solution(cycle_data)
369 |
370 |
371 | %% Solve the optimization problem
372 | [cycle_data,x_opt,f_opt,exitflag,output,lambda] = solve_optimization_problem(fixed_parameters,optimization_problem);
373 | save_solution(cycle_data, project_name, results_path)
374 |
375 | %% Plot the optimal solution
376 | filename_suffix = 'optimal';
377 | create_plots(x_opt,fixed_parameters,filename_suffix);
378 | print_solution(cycle_data)
379 |
380 |
381 |
382 |
--------------------------------------------------------------------------------
/examples/sCO2/sCO2.m:
--------------------------------------------------------------------------------
1 | %% RankineLab - A MATLAB program to optimize Rankine cycles
2 | % Authors: Roberto Agromayor
3 | % Date: Spring 2021
4 |
5 |
6 | %% Initialize the program
7 | % Clear all variables and close all figures
8 | clear all
9 | close all
10 | clc
11 |
12 | % Add the path to the 'source_code' directory
13 | % The function genpath() is very convenient
14 | addpath(genpath('../../source_code'))
15 |
16 | % Set a project name (mfilename corresponds to the script name)
17 | project_name = mfilename;
18 |
19 | % Create a directory to store the figures and results
20 | results_path = fullfile(pwd, [project_name, '_results']);
21 | if exist(results_path, 'dir') ~= 7 % 7 is a MATLAB's convention
22 | mkdir(results_path)
23 | else
24 | rmdir(results_path, 's')
25 | mkdir(results_path)
26 | end
27 |
28 |
29 | %% Define the thermodynamic specifications and cycle parameters
30 | % Ambient state
31 | p_0 = 101325; % Ambient pressure
32 | T_0 = 30+273.15; % Ambient temperature
33 |
34 | % Define the working fluids
35 | heating_fluid = 'HEOS::Air';
36 | working_fluid = 'HEOS::CO2';
37 | cooling_fluid = 'HEOS::Water';
38 |
39 | % Some guidance to select the fluid name and EoS
40 | %{
41 |
42 | You can set the back-end used to compute the thermodynamic properties by
43 | precedding the fluid name by 'HEOS::' (for the Coolprop back-end) or by
44 | 'REFPROP::' (for the REFPROP backend).
45 |
46 | You can check the list of the CoolProp back-end fluid names here:
47 | http://www.coolprop.org/fluid_properties/PurePseudoPure.html
48 |
49 | Note that the fluid names for REFPROP may be different
50 |
51 | The equations of state may fail for some thermodynamic states and break
52 | down the optimization progress (oh, the horror...)
53 |
54 | This is depedent on the fluid and the EoS back-end (REFPROP/CoolProp)
55 |
56 | My recommendation is to try the CoolProp back-end first
57 | 1) CoolProp EoS are (much) faster, but can fail sometimes
58 | 2) REFPROP EoS are slower, but they are also a bit more robust
59 |
60 | The worst kind of error that you can get while executing the code is
61 | that the equations of state fail.
62 |
63 | There is not much to do about it when it happens because it depends on the
64 | CoolProp/REFPROP libraries.
65 |
66 | If you encounter this problem you can try to start the optimization from a
67 | different initial guess, change the bounds/constraints of the optimization
68 | or, as a last measure, change the EoS back-to REFPROP.
69 |
70 | If all of these fail, you are out of luck...
71 |
72 | %}
73 |
74 | % Define the thermodynamic specifications of the heat source
75 | m_h = 1.00; % Heat source mass flow rate (kg/s). This variable "scales-up" the problem
76 | T_1 = 400+273.15; % Heat source inlet temperature (K)
77 | p_1 = p_0; % Heat source inlet pressure (Pa)
78 | p_3 = p_0; % Heat source outlet pressure (Pa)
79 | T_3min = 50+273.15; % Minimum temperature at the outlet of the heat source (K)
80 | T_3max = T_1; % Maximum temperature at the outlet of the heat source (K)
81 |
82 | % Define the thermodynamic specifications of the heat sink
83 | T_10 = T_0; % Heat sink inlet temperature (K)
84 | p_10 = p_0; % Heat sink inlet pressure (Pa)
85 | p_12 = p_0; % Heat sink outlet pressure (Pa)
86 | T_12min = T_0+10; % Minimum temperature at the outlet of the heat sink (K)
87 | T_12max = T_0+20; % Maximum temperature at the outlet of the heat sink (K)
88 |
89 | % Define pressure drops in the heat exchangers (% of the inlet pressure)
90 | dp_h_evap = 0.02; % Pressure drop in the heating fluid side of the evaporator (relative with respect to inlet)
91 | dp_c_evap = 0.02; % Pressure drop in the working fluid side of the evaporator (relative with respect to inlet)
92 | dp_h_cond = 0.02; % Pressure drop in the working fluid side of the condenser (relative with respect to inlet)
93 | dp_c_cond = 0.02; % Pressure drop in the cooling fluid side of the condenser (relative with respect to inlet)
94 | dp_h_rec = 0.02; % Pressure drop in the hot side of the recuperator (relative with respect to inlet)
95 | dp_c_rec = 0.02; % Pressure drop in the cold side of the recuperator (relative with respect to inlet)
96 |
97 | % Define the number of discretizations of the heat exchangers
98 | % More discretizations: more accurate pinch point and more execution time
99 | N_evap = 50; % Choose an integer
100 | N_cond = 50; % Choose an integer
101 | N_rec = 50; % Choose an integer
102 |
103 | % Define the efficiency of the pumps
104 | eta_pump_h = 0.85; % Isentropic efficiency of the heat source pump
105 | eta_pump_f = 0.85; % Isentropic efficiency of the working fluid pump
106 | eta_pump_c = 0.85; % Isentropic efficiency of the heat sink pump
107 |
108 | % Define the efficiency of the expander
109 | eta_expander = 0.90; % Efficiency of the expander
110 |
111 | % Turbomachinery efficiency definition
112 | pump_efficiency_definition = 'isentropic'; % Definition of the pump efficiency: 'isentropic' or 'polytropic'
113 | expander_efficiency_definition = 'isentropic'; % Definition of the expander efficiency: 'isentropic' or 'polytropic'
114 |
115 | % More details about the efficiency definition
116 | %{
117 |
118 | If you set efficiency_definition='isentropic' the efficiency of the
119 | working fluid pump and expander are defined as:
120 |
121 | eta_pump = (h_out_s-h_in)/(h_out-h_in)
122 | eta_expander = (h_in-h_out)/(h_in-h_out_s)
123 |
124 | and the turbomachinery computations only involve the inlet and exit states
125 |
126 | If you set efficiency_definition='polytropic' the efficiency of the working
127 | fluid pump and expander are defined as:
128 |
129 | eta_pump = dh_s/dh = 1/d*dp/dh
130 | eta_expander = dh/dh_s = d*dh/dp
131 |
132 | and the turbomachinery computations are performed by solving the previous
133 | ordinary differential equations (ODE) along the compression or expansion
134 |
135 | %}
136 |
137 |
138 | %% Define extra fluid parameters
139 | % Used to scale degrees of freedom (no need to do changes in most cases)
140 | % Define the critical properties
141 | p_crit = prop_calculation('P_CRITICAL',working_fluid); % Critical pressure
142 | T_crit = prop_calculation('T_CRITICAL',working_fluid); % Critical temperature
143 | % p_crit = [];
144 | % T_crit = [];
145 |
146 | % Define the triple properties (only pure substances)
147 | p_trip = prop_calculation('P_TRIPLE',working_fluid); % Triple pressure
148 | T_trip = prop_calculation('T_TRIPLE',working_fluid); % Triple temperature
149 | % p_trip = [];
150 | % T_trip = [];
151 |
152 | % Define the saturation pressure and enthalpy at ambient temperature
153 | % If the ambient temperature is higher than the critical temperature use
154 | % the critical pressure and enthalpy instead
155 | if T_0 < T_crit
156 | p_sat0 = prop_calculation('P','T',T_0,'Q',0,working_fluid);
157 | h_sat0 = prop_calculation('H','T',T_0,'Q',0,working_fluid);
158 | else
159 | p_sat0 = p_crit;
160 | h_sat0 = prop_calculation('H','T',T_crit,'P',p_crit,working_fluid);
161 | end
162 |
163 | % Define the pressure and temperature limits
164 | p_min = 1.01*p_trip; % Minimum pressure
165 | p_max = 5.00*p_crit; % Maximum pressure
166 | T_min = T_0; % Maximum temperature
167 | T_max = 1.50*T_crit; % Maximum temperature
168 |
169 | % Define the enthalpy limits
170 | h_min = h_sat0;
171 | h_max = prop_calculation('H','T',T_1,'P',1e-3,working_fluid);
172 |
173 |
174 | %% Define the independent variables and bounds
175 | % x1 = Heat source exit temperature
176 | x1 = 0.25;
177 | x1_min = 0.00;
178 | x1_max = 1.00;
179 |
180 | % x2 = Heat sink exit temperature
181 | x2 = 0.25;
182 | x2_min = 0.00;
183 | x2_max = 1.00;
184 |
185 | % x3 = Pump inlet pressure (subcritical)
186 | x3 = (2.0*p_sat0-p_min)/(p_max-p_min);
187 | x3_min = 0.00;
188 | x3_max = 1.00;
189 |
190 | % x4 = Pump inlet enthalpy
191 | x4 = 0.05;
192 | x4_min = 0.00;
193 | x4_max = 1.00;
194 |
195 | % x5 = Expander inlet pressure
196 | x5 = (3.00*p_crit-p_min)/(p_max-p_min);
197 | x5_min = 0.00;
198 | x5_max = 1.00;
199 |
200 | % x6 = Expander inlet enthalpy
201 | x6 = 0.80;
202 | x6_min = 0.00;
203 | x6_max = 1.00;
204 |
205 | % x7 = Recuperator effectiveness (set to zero for no recuperator)
206 | x7 = 0.25;
207 | x7_min = 0.00;
208 | x7_max = 1.00;
209 |
210 | % Organize the information in vectors
211 | lb_cycle = [x1_min, x2_min, x3_min, x4_min, x5_min, x6_min, x7_min]';
212 | ub_cycle = [x1_max, x2_max, x3_max, x4_max, x5_max, x6_max, x7_max]';
213 | x0_cycle = [x1, x2, x3, x4, x5, x6, x7]';
214 |
215 | % Some guidelines for the degrees of freedom
216 | %{
217 |
218 | Play around with x0_cycle to find a good initial guess.
219 |
220 | Mathematical definition of the degrees of freedom
221 | x1 = (T_3 - T_3min) / (T_3max - T_3min)
222 | x2 = (T_12 - T_12min) / (T_12max - T_12min)
223 | x3 = (p_4 - p_min) / (p_max - p_min)
224 | x4 = (h_4 - h_min) / (h_max - h_min)
225 | x5 = (p_7 - p_min) / (p_max - p_min)
226 | x6 = (h_7 - h_min) / (h_max - h_min)
227 | x7 = (h6 - h5) / (h(p6,T8) - h5)
228 |
229 | If you want a cycle configuration with no recuperator you have to:
230 | 1) Set the recuperator effectiveness equal to zero:
231 | x7 = x7_min = x7_max = 0.00
232 | 2) Set the pressure drops in the recuperator equal to zero:
233 | dp_h_rec = dp_c_rec = 0.00
234 | 3) Do not apply a constraint for the recuperator pinch point dT:
235 | constraints.dT_rec.apply = 'no'
236 |
237 | How to give start values when you use the code for the first time?
238 | x1 usually takes low values (maximum exploitation of the heat source)
239 | x2 usually takes low values (small temperature jump in the heat sink)
240 | x3 usually takes low values (low pressure at the exit of the condenser)
241 | x4 usually takes low values (low enthalpy at the exit of the condenser)
242 | x5x_crit for transcritical cycles
243 | x6 usually takes high values (high enthalpy at the inlet of the evap.)
244 | x7=0 corresponds to no recuperation and x=1 to ideal recuperation
245 |
246 | Note: Low means close to zero and high means close to one
247 |
248 | %}
249 |
250 |
251 | %% Define the constraints
252 | % Instructions:
253 | % 1. Specify the minimum and maximum values
254 | % 2. Specify whether to apply the constraint or not
255 | % 3. Use [brackets] to ignore the constraint value
256 |
257 | % Minimum temperature difference in the evaporator (pinch point)
258 | constraints.dT_evap.min = 10;
259 | constraints.dT_evap.apply = 'yes';
260 |
261 | % Minimum temperature difference in the condenser (pinch point)
262 | constraints.dT_cond.min = 10;
263 | constraints.dT_cond.apply = 'yes';
264 |
265 | % Minimum temperature difference in the recuperator (pinch point)
266 | constraints.dT_rec.min = 10;
267 | constraints.dT_rec.apply = 'yes';
268 |
269 | % Minimum vapor quality along the expander
270 | constraints.quality.min = 1.00;
271 | constraints.quality.apply = 'yes';
272 |
273 | % Degree of subcooling at the inlet of the pump
274 | constraints.dT_subcooling.min = 1;
275 | constraints.dT_subcooling.max = [];
276 | constraints.dT_subcooling.apply = 'no';
277 |
278 | % Degree of superheating at inlet of the expander (subcritical cycles)
279 | constraints.dT_superheating.min = 5;
280 | constraints.dT_superheating.max = [];
281 | constraints.dT_superheating.apply = 'no';
282 |
283 | % Maximum cycle pressure
284 | constraints.pressure.min = [];
285 | constraints.pressure.max = 300e5;
286 | constraints.pressure.apply = 'no';
287 |
288 |
289 | %% Define optimization algorithm settings
290 | % Set optimization algorithm
291 | % 'spq' is my favourite because it converges reliably and respects bounds
292 | % 'active-set' is a bit more aggressive and does not always respect the
293 | % bounds. It is faster, but less reliable, than 'sqp'.
294 | % 'interior-point' also works, but it requires more iterations
295 | algorithm = 'sqp';
296 |
297 | % Compute the problem gradients in parallel or not
298 | use_parallel = false; % true or false
299 |
300 | % Define termination criteria (no need to change in most cases)
301 | max_iterations = 1000;
302 | max_function_evals = 10000;
303 | step_tolerance = 1e-08;
304 | function_tolerance = 1e-05;
305 | constraint_tolerance = 1e-05;
306 | optimality_tolerance = 1e-03;
307 |
308 | % Description of the possible outputs of the optimization function
309 | %{
310 |
311 | 'interior-point', 'active-set', and 'sqp' algorithms
312 | Exitflag = 1 -> Success. First-order optimality measure was less than options and constraints are not violated.
313 | Exitflag = 2 -> Success. Step size was less than options and constraints are not violated.
314 | Exitflag = 0 -> Unsuccess. Number of iterations or function evaluations exceeded option
315 | Exitflag = -1 -> Unsuccess. Solver stopped by an output function
316 | Exitflag = -2 -> Unsuccess. No feasible point was found
317 |
318 | Only active set algorithm
319 | Exitflag = 4 -> Success. Magnitude of the search direction was less than 2*options.StepTolerance and maximum constraint violation was less than options.ConstraintTolerance.
320 | Exitflag = 5 -> Success. Magnitude of directional derivative in search direction was less than 2*options.OptimalityTolerance and maximum constraint violation was less than options.ConstraintTolerance.
321 |
322 | %}
323 |
324 |
325 | %% Choose what figures should be plotted
326 | choose_plots = struct('diagram_TQ', 'yes', ... % Temperature - heat duty diagram
327 | 'diagram_Ts', 'yes', ... % Temperature - entropy diagram of the cycle
328 | 'diagram_Th', 'yes', ... % Temperature - enthalpy diagram of the cycle
329 | 'save', 0); % Choose whether to save the figures or not
330 |
331 | % Description of the saving options
332 | %{
333 |
334 | save=0 does not save the figures
335 | save=1 saves the figure in vector format using the default MATLAB export function (faster)
336 | save=2 saves the figure in vector using the export_fig library (requires ghostscript)
337 |
338 | In order to use save=2 it is necessary to install 'ghoscript'
339 | https://github.com/altmany/export_fig
340 | http://www.ghostscript.com
341 | http://xpdfreader.com
342 |
343 | %}
344 |
345 |
346 | %% Store the parameters defined up to this point into data structures
347 | % The script 'create_problem_structures' located in source_code folder
348 | % 1) 'fixed_parameters' stores the cycle specifications
349 | % 2) 'optimization_problem' stores the optimization problem settings
350 | create_problem_structures
351 |
352 | % These data structures are created in a different script to keep the
353 | % number of lines of this script to a minimum
354 |
355 | % Be tidy and clear the worskpace now that we stored everything
356 | clearvars -except optimization_problem fixed_parameters project_name results_path
357 |
358 |
359 | %% Load a previous solution as initial guess
360 | % % Uncomment these lines to use a previous solution as initial guess
361 | % load(fullfile(fixed_parameters.results_path,'cycle_data.mat'))
362 | % optimization_problem.x0 = cycle_data.optimization.x;
363 |
364 |
365 | %% Plot the initial solution
366 | filename_suffix = 'initial';
367 | cycle_data = create_plots(optimization_problem.x0,fixed_parameters,filename_suffix);
368 | print_solution(cycle_data)
369 |
370 |
371 | %% Solve the optimization problem
372 | [cycle_data,x_opt,f_opt,exitflag,output,lambda] = solve_optimization_problem(fixed_parameters,optimization_problem);
373 | save_solution(cycle_data, project_name, results_path)
374 |
375 | %% Plot the optimal solution
376 | filename_suffix = 'optimal';
377 | create_plots(x_opt,fixed_parameters,filename_suffix);
378 | print_solution(cycle_data)
379 |
380 |
381 |
382 |
--------------------------------------------------------------------------------
/source_code/create_data_structure.m:
--------------------------------------------------------------------------------
1 | function cycle_data = create_data_structure
2 |
3 | % This function is not really necessary for the computations since it is
4 | % not necessary to declare variables in MATLAB
5 | % It can be used as a reference where the cycle variables are documented
6 |
7 | % States of the thermodynamic cycle
8 | cycle_states = struct('fluid', [], ... % Fluid name
9 | 'p', [], ... % Pressure [kPa]
10 | 'T', [], ... % Temperature [K]
11 | 'd', [], ... % Density [kg/m3]
12 | 'h', [], ... % Enthalpy [J/kg]
13 | 's', [], ... % Entropy [J/kg K]
14 | 'e', []); % Exergy [J/kg]
15 |
16 | cycle_states(1:7) = cycle_states;
17 |
18 | %Fluid properties
19 | properties = struct('p_0', [], ... % Ambient pressure
20 | 'T_0', [], ... % Ambient temperature
21 | 'p_crit', [], ... % Critical pressure
22 | 'T_crit', [], ... % Critical temperature
23 | 'p_trip', [], ... % Triple pressure
24 | 'T_trip', []); % Triple temperature
25 |
26 | % Working fluids
27 | fluids = [];
28 |
29 |
30 | % Mass flows
31 | mass_flows = struct('m_h', [], ... % Heating fluid mass flow rate [kg/s]
32 | 'm_f', [], ... % Working fluid mass flow rate [kg/s]
33 | 'm_c', []); % Cooling fluid mass flow rate [kg/s]
34 |
35 |
36 | % Energy flows
37 | energy_flows = struct('Q_max', [], ... % Heat flow rate if the heat source is cooled down to ambient temperature [W]
38 | 'Q_evap', [], ... % Heat flow rate absorbed in the heat exchanger [W]
39 | 'W_exp', [], ... % Power delivered by the expander [W]
40 | 'W_pump_h', [], ... % Power consumed by the pump [W]
41 | 'W_pump_f', [], ... % Power consumed by the pump [W]
42 | 'W_pump_c', []); % Power consumed by the pump [W]
43 |
44 |
45 | % % Exergy flows
46 | exergy_flows = struct('E_max', [], ... % Exergy flow if the heat source is cooled down to ambient temperature [W]
47 | 'I_evap', [], ... % Exergy destruction in the heat exchanger [W]
48 | 'I_cond', [], ... % Exergy destruction in the heat exchanger [W]
49 | 'I_rec', [], ... % Exergy destruction in the heat exchanger [W]
50 | 'I_pump_h', [], ... % Exergy destruction in the pump [W]
51 | 'I_pump_f', [], ... % Exergy destruction in the pump [W]
52 | 'I_pump_c', [], ... % Exergy destruction in the pump [W]
53 | 'I_exp', [], ... % Exergy destruction in the expander [W]
54 | 'I_source', [], ... % Exergy flow at the exit of the heat source [W]
55 | 'I_sink', []); % Exergy flow at the exit of the heat sink [W]
56 |
57 |
58 | % Efficiencies of the cycle
59 | efficiency = struct('eta_1', [], ... % Plant energy efficiency
60 | 'eta_1recovery', [], ... % Energy recovery efficiency
61 | 'eta_1cycle', [], ... % Cycle energy efficiency
62 | 'eta_2', [], ... % Plant exergy efficiency
63 | 'eta_2recovery', [], ... % Exergy recovery efficiency
64 | 'eta_2cycle', []); % Cycle exergy efficiency
65 |
66 |
67 | % Variables associated with the expander
68 | expander = struct('N', [], ... % Number of discretizations
69 | 'p', [], ... % Pressure [kPa]
70 | 'T', [], ... % Temperature [K]
71 | 'd', [], ... % Density [kg/m3]
72 | 'q', [], ... % Quality [-]
73 | 'h', [], ... % Enthalpy [J/kg]
74 | 's', [], ... % Entropy [J/kg K]
75 | 'eta', []); % Polytropic efficiency
76 |
77 | % Variables associated with the pump
78 | pump = struct('N', [], ... % Number of discretizations
79 | 'p', [], ... % Pressure [kPa]
80 | 'T', [], ... % Temperature [K]
81 | 'd', [], ... % Density [kg/m3]
82 | 'q', [], ... % Quality [-]
83 | 'h', [], ... % Enthalpy [J/kg]
84 | 's', [], ... % Entropy [J/kg K]
85 | 'eta', []); % Polytropic efficiency
86 |
87 |
88 | % Variables associated with the heat exchanger
89 | exchanger = struct('N', [], ... % Number of discretizations
90 | 'p_h', [], ... % Pressure [kPa]
91 | 'p_c', [], ... % Pressure [kPa]
92 | 'T_h', [], ... % Temperature [K]
93 | 'T_c', [], ... % Temperature [K]
94 | 'd_h', [], ... % Density [kg/m3]
95 | 'd_c', [], ... % Density [kg/m3]
96 | 'h_h', [], ... % Enthalpy [J/kg]
97 | 'h_c', [], ... % Enthalpy [J/kg]
98 | 's_h', [], ... % Entropy [J/kg K]
99 | 's_c', [], ... % Entropy [J/kg K]
100 | 'dT_min', []); % Pinch point [K]
101 |
102 |
103 | % Variables associated with the optimization problem
104 | optimization = struct('x', [], ... % Vector of degrees of freedom
105 | 'lb', [], ... % Vector of upper bounds
106 | 'ub', [], ... % Vector of lower bounds
107 | 'c', [], ... % Vector of inequality constraints
108 | 'c_eq', []); % Vector of equality constraints
109 |
110 |
111 |
112 | % Create the cycle_data structure grouping the sub-structures
113 | cycle_data = struct('cycle_states', cycle_states, ...
114 | 'properties', properties, ...
115 | 'fluids', fluids, ...
116 | 'mass_flows', mass_flows, ...
117 | 'energy_flows', energy_flows, ...
118 | 'exergy_flows', exergy_flows, ...
119 | 'efficiency', efficiency, ...
120 | 'evaporator', exchanger, ...
121 | 'condenser', exchanger, ...
122 | 'recuperator', exchanger, ...
123 | 'expander', expander, ...
124 | 'pump_h', pump, ...
125 | 'pump_f', pump, ...
126 | 'pump_c', pump, ...
127 | 'optimization', optimization);
128 |
129 |
130 | end
131 |
--------------------------------------------------------------------------------
/source_code/create_problem_structures.m:
--------------------------------------------------------------------------------
1 | %% Save the cycle parameters as a structure
2 | % Simple script to organize information into an structure
3 |
4 | % Thermodynamic boundaries
5 | boundary_conditions = struct('heating_fluid', {heating_fluid}, ...
6 | 'working_fluid', {working_fluid}, ...
7 | 'cooling_fluid', {cooling_fluid}, ...
8 | 'm_h', m_h, ...
9 | 'T_1', T_1, ...
10 | 'p_1', p_1, ...
11 | 'p_3', p_3, ...
12 | 'T_3min', T_3min, ...
13 | 'T_3max', T_3max, ...
14 | 'T_10', T_10, ...
15 | 'p_10', p_10, ...
16 | 'p_12', p_12, ...
17 | 'T_12min', T_12min, ...
18 | 'T_12max', T_12max);
19 |
20 | % Fluid properties
21 | properties = struct('p_0', p_0, ...
22 | 'T_0', T_0, ...
23 | 'p_crit', p_crit, ...
24 | 'T_crit', T_crit, ...
25 | 'p_trip', p_trip, ...
26 | 'T_trip', T_trip, ...
27 | 'p_max', p_max, ...
28 | 'T_max', T_max, ...
29 | 'h_max', h_max, ...
30 | 'p_min', p_min, ...
31 | 'T_min', T_min, ...
32 | 'h_min', h_min);
33 |
34 | % Component specifications
35 | components = struct('dp_h_evap', dp_h_evap, ...
36 | 'dp_c_evap', dp_c_evap, ...
37 | 'dp_h_cond', dp_h_cond, ...
38 | 'dp_c_cond', dp_c_cond, ...
39 | 'dp_h_rec', dp_h_rec, ...
40 | 'dp_c_rec', dp_c_rec, ...
41 | 'N_evap', N_evap, ...
42 | 'N_cond', N_cond, ...
43 | 'N_rec', N_rec, ...
44 | 'eta_pump_h', eta_pump_h, ...
45 | 'eta_pump_f', eta_pump_f, ...
46 | 'eta_pump_c', eta_pump_c, ...
47 | 'eta_expander', eta_expander, ...
48 | 'pump_efficiency_definition', pump_efficiency_definition, ...
49 | 'expander_efficiency_definition', expander_efficiency_definition);
50 |
51 | % Lower bounds for the degrees of freedom
52 | lower_bounds = struct('x1', x1_min, ...
53 | 'x2', x2_min, ...
54 | 'x3', x3_min, ...
55 | 'x4', x4_min, ...
56 | 'x5', x5_min, ...
57 | 'x6', x6_min, ...
58 | 'x7', x7_min);
59 |
60 | % Upper bounds for the degrees of freedom
61 | upper_bounds = struct('x1', x1_max, ...
62 | 'x2', x2_max, ...
63 | 'x3', x3_max, ...
64 | 'x4', x4_max, ...
65 | 'x5', x5_max, ...
66 | 'x6', x6_max, ...
67 | 'x7', x7_max);
68 |
69 | % Organize the previous structures in a compact way
70 | fixed_parameters = struct('boundary_conditions', boundary_conditions, ...
71 | 'properties', properties, ...
72 | 'components', components, ...
73 | 'lower_bounds', lower_bounds, ...
74 | 'upper_bounds', upper_bounds, ...
75 | 'constraints', constraints, ...
76 | 'results_path', results_path, ...
77 | 'project_name', project_name, ...
78 | 'choose_plots', choose_plots);
79 |
80 |
81 | %% Create optimization_problem structure
82 | optimization_problem = struct('lb', [], ... % Vector of lower bounds
83 | 'ub', [], ... % Vector of upper bounds
84 | 'Aeq', [], ... % Matrix for linear equality constraints
85 | 'beq', [], ... % Vector for linear equality constraints
86 | 'Aineq', [], ... % Matrix for linear inequality constraints
87 | 'bineq', [], ... % Vector for linear inequality constraints
88 | 'nonlcon', [], ... % Nonlinear constraints function
89 | 'objective', [], ... % Objective function
90 | 'x0', [], ... % Initial guess for the degrees of freedom
91 | 'options', [], ... % Optimization options structure
92 | 'solver', 'fmincon');
93 |
94 | % Define the initial guess vector
95 | optimization_problem.x0 = x0_cycle;
96 |
97 | % Define the vector of lower bounds
98 | optimization_problem.lb = lb_cycle;
99 |
100 | % Define the vector of upper bounds
101 | optimization_problem.ub = ub_cycle;
102 |
103 | % Define the options using the optimoptions function
104 | % Change the type of algorithm here
105 | optimization_problem.options = optimoptions(@fmincon, ...
106 | 'Display', 'iter-detailed', ...
107 | 'Algorithm', algorithm, ...
108 | 'StepTolerance', step_tolerance, ...
109 | 'ConstraintTolerance', constraint_tolerance, ...
110 | 'OptimalityTolerance', optimality_tolerance, ...
111 | 'FunctionTolerance', function_tolerance, ...
112 | 'MaxFunctionEvaluations', max_function_evals, ...
113 | 'MaxIterations', max_iterations, ...
114 | 'FiniteDifferenceStepSize', sqrt(eps), ...
115 | 'UseParallel', use_parallel, ...
116 | 'PlotFcn', {@optimplotfval, ...
117 | @optimplotconstrviolation, ...
118 | @optimplotfirstorderopt, ...
119 | @optimplotstepsize});
120 |
121 |
122 | optimization_problem.options.OutputFcn = @(x,optimValues,state)save_current_solution(x,optimValues,state,fixed_parameters);
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/source_code/evaluate_compressor.m:
--------------------------------------------------------------------------------
1 | function [h_high,p,h,T,s,d] = evaluate_compressor(fluid,h_low,p_low,p_high,efficiency,efficiency_definition,calc_detail)
2 |
3 | if strcmp(efficiency_definition,'isentropic') == 1
4 |
5 | % Isentropic efficiency computation
6 | s = prop_calculation('S','P',p_low,'H',h_low,fluid);
7 | h_high_s = prop_calculation('H','P',p_high,'S',s,fluid);
8 | h_high = h_low+(h_high_s-h_low)/efficiency;
9 | p = [p_low p_high]';
10 | h = [h_low h_high]';
11 |
12 | elseif strcmp(efficiency_definition,'polytropic') == 1
13 |
14 | % Polytropic efficiency computation
15 | options = odeset('RelTol',1e-6,'AbsTol',1e-6);
16 | [p,h] = ode45(@(p,h)R(p,h,fluid,efficiency),linspace(p_low,p_high,25),h_low,options);
17 | h_high = h(end);
18 |
19 | else
20 |
21 | error("The efficiency definition must be 'isentropic' or 'polytropic'")
22 |
23 | end
24 |
25 | % Compute the other thermodynamic variables
26 | if strcmp(calc_detail,'short')
27 | T = 0*p; s = 0*p; d = 0*p;
28 | elseif strcmp(calc_detail,'long')
29 | T = 0*p; s = 0*p; d = 0*p;
30 | for i = 1:length(p)
31 | T(i) = prop_calculation('T','P',p(i),'H',h(i),fluid);
32 | s(i) = prop_calculation('S','P',p(i),'H',h(i),fluid);
33 | d(i) = prop_calculation('D','P',p(i),'H',h(i),fluid);
34 | end
35 | end
36 |
37 | end
38 |
39 | function dhdp = R(p,h,fluid,efficiency)
40 | rho = prop_calculation('D','P',p,'H',h,fluid);
41 | dhdp = 1/efficiency/rho;
42 | end
43 |
44 |
45 | % N = 10;
46 | % dp = (p_high-p_low)/(N-1);
47 | % p = (p_low:dp:p_high)';
48 | % h = zeros(N,1);
49 | % h(1) = h_low;
50 | % for n = 1:N-1
51 | % h(n+1) = h(n)+dp*R(p(n),h(n),fluid,eta_poly);
52 | % end
53 | % h_high = h(end);
--------------------------------------------------------------------------------
/source_code/evaluate_exchanger.m:
--------------------------------------------------------------------------------
1 | function [dT,T_h,T_c,h_h,h_c,p_h,p_c,d_h,d_c,s_h,s_c] = evaluate_exchanger(fluid_h,fluid_c,m_h,m_c,p_h1,p_h2,p_c1,p_c2,h_h1,h_h2,h_c1,h_c2,N,calc_detail)
2 | %% Preliminary computations
3 |
4 | % Compute the mass flow rate ratio
5 | m = m_h/m_c;
6 |
7 | % Compute the temperature difference at the inlet
8 | T_h1 = prop_calculation('T','P',p_h1,'H',h_h1,fluid_h);
9 | T_c1 = prop_calculation('T','P',p_c1,'H',h_c1,fluid_c);
10 |
11 |
12 | %% Discretize the heat exchanger in N nodes
13 | % Discretize the heat exchanger in N nodes
14 | dq = (h_h2-h_h1)/(N-1); % Heat exchange step
15 | dp_h = (p_h2-p_h1)/(N-1); % Hot pressure drop step
16 | dp_c = (p_c2-p_c1)/(N-1); % Cold pressure drop step
17 |
18 | % Preallocate memory
19 | h_h = zeros(N,1); h_c = zeros(N,1);
20 | T_h = zeros(N,1); T_c = zeros(N,1);
21 | p_h = zeros(N,1); p_c = zeros(N,1);
22 |
23 | % Initialize variables
24 | h_h(1) = h_h1; h_c(1) = h_c1;
25 | T_h(1) = T_h1; T_c(1) = T_c1;
26 | p_h(1) = p_h1; p_c(1) = p_c1;
27 |
28 | % Main loop
29 | for i = 1:N-1
30 | h_h(i+1) = h_h(i)+dq;
31 | h_c(i+1) = h_c(i)+dq*m;
32 | p_h(i+1) = p_h(i)+dp_h;
33 | p_c(i+1) = p_c(i)+dp_c;
34 | T_h(i+1) = prop_calculation('T','P',p_h(i+1),'H',h_h(i+1),fluid_h);
35 | T_c(i+1) = prop_calculation('T','P',p_c(i+1),'H',h_c(i+1),fluid_c);
36 | % q_h(i+1) = prop_calculation('Q','P',p_h(i+1),'H',h_h(i+1),fluid_h);
37 | % q_c(i+1) = prop_calculation('Q','P',p_c(i+1),'H',h_c(i+1),fluid_c);
38 | end
39 |
40 | % I am not satisfied with the solution adding extra nodes at phase changes
41 | % The linear pressure drop with heat transfer is kept to have a close
42 | % thermodynamic diagram when plotting
43 | % I think that the extra programming complexity and loss of robustness is
44 | % not worth the extra accuracy at the phase changes
45 | % If an accurate cycle simulation is desired the number of the
46 | % discretizations can be increased after a local optima has been found
47 |
48 |
49 | %% Compute the other thermodynamic variables
50 | if strcmp(calc_detail,'short')
51 | d_h = zeros(N,1); d_c = zeros(N,1); s_h = zeros(N,1); s_c = zeros(N,1);
52 | elseif strcmp(calc_detail,'long')
53 | d_h = zeros(N,1); d_c = zeros(N,1); s_h = zeros(N,1); s_c = zeros(N,1);
54 | for i = 1:N
55 | d_h(i) = prop_calculation('D','P',p_h(i),'H',h_h(i),fluid_h);
56 | d_c(i) = prop_calculation('D','P',p_c(i),'H',h_c(i),fluid_c);
57 | s_h(i) = prop_calculation('S','P',p_h(i),'H',h_h(i),fluid_h);
58 | s_c(i) = prop_calculation('S','P',p_c(i),'H',h_c(i),fluid_c);
59 | end
60 | end
61 |
62 |
63 | %% Compute the pinch point temperature difference
64 | dT = T_h-T_c;
65 | % dT_min = min(dT);
66 |
67 |
68 | end
69 |
--------------------------------------------------------------------------------
/source_code/evaluate_expander.m:
--------------------------------------------------------------------------------
1 | function [h_low,p,h,T,s,d] = evaluate_expander(fluid,h_high,p_high,p_low,efficiency,efficiency_definition,calc_detail)
2 |
3 | if strcmp(efficiency_definition,'isentropic') == 1
4 |
5 | % Isentropic efficiency computation
6 | s = prop_calculation('S','P',p_high,'H',h_high,fluid);
7 | h_low_s = prop_calculation('H','P',p_low,'S',s,fluid);
8 | h_low = h_high-(h_high-h_low_s)*efficiency;
9 | p = [p_low p_high]';
10 | h = [h_low h_high]';
11 |
12 | elseif strcmp(efficiency_definition,'polytropic') == 1
13 |
14 | % Polytropic efficiency computation
15 | options = odeset('RelTol',1e-6,'AbsTol',1e-6);
16 | [p,h] = ode45(@(p,h)R(p,h,fluid,efficiency),linspace(p_high,p_low,25),h_high,options);
17 | h_low = h(end);
18 |
19 | else
20 |
21 | error("The efficiency definition must be 'isentropic' or 'polytropic'")
22 |
23 | end
24 |
25 | % Compute the other thermodynamic variables
26 | if strcmp(calc_detail,'short')
27 | T = 0*p; s = 0*p; d = 0*p;
28 | elseif strcmp(calc_detail,'long')
29 | T = 0*p; s = 0*p; d = 0*p;
30 | for i = 1:length(p)
31 | T(i) = prop_calculation('T','P',p(i),'H',h(i),fluid);
32 | s(i) = prop_calculation('S','P',p(i),'H',h(i),fluid);
33 | d(i) = prop_calculation('D','P',p(i),'H',h(i),fluid);
34 | end
35 | end
36 |
37 | end
38 |
39 | function dhdp = R(p,h,fluid,efficiency)
40 | rho = prop_calculation('D','P',p,'H',h,fluid);
41 | dhdp = efficiency/rho;
42 | end
43 |
44 | % N = 10;
45 | % dp = (p_low-p_high)/(N-1);
46 | % p = (p_high:dp:p_low)';
47 | % h = zeros(N,1);
48 | % h(1) = h_high;
49 | % for n = 1:N-1
50 | % h(n+1) = h(n)+dp*R(p(n),h(n),fluid,eta_poly);
51 | % end
52 | % h_low = h(end);
--------------------------------------------------------------------------------
/source_code/evaluate_optimization_problem.m:
--------------------------------------------------------------------------------
1 | function [cycle_data, f, c, c_eq] = evaluate_optimization_problem(x,fixed_parameters)
2 |
3 | % Evaluate the thermodynamic cycle model
4 | cycle_data = evaluate_rankine_cycle(x,fixed_parameters);
5 |
6 | % Extract the objective function value
7 | f = -[cycle_data.efficiency.eta_1];
8 | % f = -[cycle_data.efficiency.eta_2];
9 |
10 | % Extract the vector of inequality constraints
11 | c = cycle_data.optimization.c;
12 |
13 | % Extract the vector of equality constraints
14 | c_eq = cycle_data.optimization.c_eq;
15 |
16 | end
17 |
18 |
--------------------------------------------------------------------------------
/source_code/export_fig/.gitignore:
--------------------------------------------------------------------------------
1 | /.ignore
2 | *.txt
3 | *.asv
4 | *~
5 | *.mex*
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/Export_fig.prj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/source_code/export_fig/ImageSelection.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turbo-sim/RankineLab/f09b7ee6ddc17f0987951fc74d79dc2c02faf829/source_code/export_fig/ImageSelection.class
--------------------------------------------------------------------------------
/source_code/export_fig/ImageSelection.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/turbo-sim/RankineLab/f09b7ee6ddc17f0987951fc74d79dc2c02faf829/source_code/export_fig/ImageSelection.java
--------------------------------------------------------------------------------
/source_code/export_fig/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014, Oliver J. Woodford, Yair M. Altman
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * Neither the name of the {organization} nor the names of its
15 | contributors may be used to endorse or promote products derived from
16 | this software without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/source_code/export_fig/append_pdfs.m:
--------------------------------------------------------------------------------
1 | function append_pdfs(varargin)
2 | %APPEND_PDFS Appends/concatenates multiple PDF files
3 | %
4 | % Example:
5 | % append_pdfs(outputFilename, inputFilename1, inputFilename2, ...)
6 | % append_pdfs(outputFilename, inputFilenames_list{:})
7 | % append_pdfs(outputFilename, inputFilenames_cell_or_string_array)
8 | % append_pdfs output.pdf input1.pdf input2.pdf
9 | %
10 | % This function appends multiple PDF files to an existing PDF file, or
11 | % concatenates them into a PDF file if the output file doesn't yet exist.
12 | %
13 | % This function requires that you have ghostscript installed on your
14 | % system. Ghostscript can be downloaded from: http://www.ghostscript.com
15 | %
16 | % IN:
17 | % output - string of output file name (including the extension, .pdf).
18 | % If it exists it is appended to; if not, it is created.
19 | % input1 - string of an input file name (including the extension, .pdf).
20 | % All input files are appended in order.
21 | % input_list - cell array list of input file name strings. All input
22 | % files are appended in order.
23 |
24 | % Copyright: Oliver Woodford, 2011-2014, Yair Altman 2015-
25 |
26 | %{
27 | % Thanks to Reinhard Knoll for pointing out that appending multiple pdfs in
28 | % one go is much faster than appending them one at a time.
29 |
30 | % Thanks to Michael Teo for reporting the issue of a too long command line.
31 | % Issue resolved on 5/5/2011, by passing gs a command file.
32 |
33 | % Thanks to Martin Wittmann for pointing out quality issue when appending bitmaps
34 | % Issue resolved (to best of my ability) 1/6/2011, using the prepress setting
35 |
36 | % 26/02/15: If temp dir is not writable, use the output folder for temp
37 | % files when appending (Javier Paredes); sanity check of inputs
38 | % 24/01/18: Fixed error in case of existing output file (append mode)
39 | % 24/01/18: Fixed issue #213: non-ASCII characters in folder names on Windows
40 | % 06/12/18: Avoid an "invalid escape-char" warning upon error
41 | % 22/03/20: Alert if ghostscript.m is not found on Matlab path
42 | % 29/03/20: Accept a cell-array of input files (issue #299); accept both "strings", 'chars'
43 | %}
44 |
45 | if nargin < 2, return; end % sanity check
46 |
47 | % Convert strings => chars; strtrim extra spaces
48 | varargin = cellfun(@str2char,varargin,'un',false);
49 |
50 | % Convert cell array into individual strings (issue #299)
51 | if nargin==2 && iscell(varargin{2})
52 | varargin = {varargin{1} varargin{2}{:}}; %#ok
53 | end
54 |
55 | % Ensure that ghostscript() exists on the Matlab path
56 | if ~exist('ghostscript','file')
57 | error('export_fig:append_pdfs:ghostscript', 'The ghostscript.m function is required by append_pdf.m. Install the complete export_fig package from https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig or https://github.com/altmany/export_fig')
58 | end
59 |
60 | % Are we appending or creating a new file
61 | append = exist(varargin{1}, 'file') == 2;
62 | output = [tempname '.pdf'];
63 | try
64 | % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
65 | fid = fopen(output,'w');
66 | fwrite(fid,1);
67 | fclose(fid);
68 | delete(output);
69 | isTempDirOk = true;
70 | catch
71 | % Temp dir is not writable, so use the output folder
72 | [dummy,fname,fext] = fileparts(output); %#ok
73 | fpath = fileparts(varargin{1});
74 | output = fullfile(fpath,[fname fext]);
75 | isTempDirOk = false;
76 | end
77 | if ~append
78 | output = varargin{1};
79 | varargin = varargin(2:end);
80 | end
81 |
82 | % Create the command file
83 | if isTempDirOk
84 | cmdfile = [tempname '.txt'];
85 | else
86 | cmdfile = fullfile(fpath,[fname '.txt']);
87 | end
88 | prepareCmdFile(cmdfile, output, varargin{:});
89 |
90 | % Call ghostscript
91 | [status, errMsg] = ghostscript(['@"' cmdfile '"']);
92 |
93 | % Check for ghostscript execution errors
94 | if status && ~isempty(strfind(errMsg,'undefinedfile')) && ispc %#ok
95 | % Fix issue #213: non-ASCII characters in folder names on Windows
96 | for fileIdx = 2 : numel(varargin)
97 | [fpath,fname,fext] = fileparts(varargin{fileIdx});
98 | varargin{fileIdx} = fullfile(normalizePath(fpath),[fname fext]);
99 | end
100 | % Rerun ghostscript with the normalized folder names
101 | prepareCmdFile(cmdfile, output, varargin{:});
102 | [status, errMsg] = ghostscript(['@"' cmdfile '"']);
103 | end
104 |
105 | % Delete the command file
106 | delete(cmdfile);
107 |
108 | % Check for ghostscript execution errors
109 | if status
110 | errMsg = strrep(errMsg,'\','\\'); % Avoid an "invalid escape-char" warning
111 | error('YMA:export_fig:append_pdf',errMsg);
112 | end
113 |
114 | % Rename the file if needed
115 | if append
116 | movefile(output, varargin{1}, 'f');
117 | end
118 | end
119 |
120 | % Prepare a text file with ghostscript directives
121 | function prepareCmdFile(cmdfile, output, varargin)
122 | fh = fopen(cmdfile, 'w');
123 | fprintf(fh, '-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="%s" -f', output);
124 | fprintf(fh, ' "%s"', varargin{:});
125 | fclose(fh);
126 | end
127 |
128 | % Convert long/non-ASCII folder names into their short ASCII equivalents
129 | function pathStr = normalizePath(pathStr)
130 | [fpath,fname,fext] = fileparts(pathStr);
131 | if isempty(fpath) || strcmpi(fpath,pathStr), return, end
132 | dirOutput = evalc(['system(''dir /X /AD "' pathStr '*"'')']);
133 | shortName = strtrim(regexprep(dirOutput,{'.*> *',[fname fext '.*']},''));
134 | if isempty(shortName)
135 | shortName = [fname fext];
136 | end
137 | fpath = normalizePath(fpath); %recursive until entire fpath is processed
138 | pathStr = fullfile(fpath, shortName);
139 | end
140 |
141 | % Convert a possible string => char
142 | function value = str2char(value)
143 | try
144 | value = controllib.internal.util.hString2Char(value);
145 | catch
146 | if isa(value,'string')
147 | value = char(value);
148 | end
149 | end
150 | value = strtrim(value);
151 | end
152 |
--------------------------------------------------------------------------------
/source_code/export_fig/copyfig.m:
--------------------------------------------------------------------------------
1 | function fh = copyfig(fh)
2 | %COPYFIG Create a copy of a figure, without changing the figure
3 | %
4 | % Examples:
5 | % fh_new = copyfig(fh_old)
6 | %
7 | % This function will create a copy of a figure, but not change the figure,
8 | % as copyobj sometimes does, e.g. by changing legends.
9 | %
10 | % IN:
11 | % fh_old - The handle of the figure to be copied. Default: gcf.
12 | %
13 | % OUT:
14 | % fh_new - The handle of the created figure.
15 |
16 | % Copyright (C) Oliver Woodford 2012, Yair Altman 2015
17 |
18 | % 26/02/15: If temp dir is not writable, use the dest folder for temp
19 | % destination files (Javier Paredes)
20 | % 15/04/15: Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02)
21 | % 09/09/18: Fix issue #252: Workaround for cases where copyobj() fails for any reason
22 |
23 | % Set the default
24 | if nargin == 0
25 | fh = gcf;
26 | end
27 | % Is there a legend?
28 | useCopyobj = isempty(findall(fh, 'Type', 'axes', 'Tag', 'legend'));
29 | if useCopyobj
30 | % Safe to copy using copyobj
31 | oldWarn = warning('off'); %Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02)
32 | try
33 | fh = copyobj(fh, 0);
34 | catch
35 | % Fix issue #252: Workaround for cases where copyobj() fails for any reason
36 | useCopyobj = false; % if copyobj() croaks, use file save/load below
37 | end
38 | warning(oldWarn);
39 | end
40 | if ~useCopyobj
41 | % copyobj will change the figure, so save and then load it instead
42 | tmp_nam = [tempname '.fig'];
43 | try
44 | % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
45 | fid = fopen(tmp_nam,'w');
46 | fwrite(fid,1);
47 | fclose(fid);
48 | delete(tmp_nam); % cleanup
49 | catch
50 | % Temp dir is not writable, so use the current folder
51 | [dummy,fname,fext] = fileparts(tmp_nam); %#ok
52 | fpath = pwd;
53 | tmp_nam = fullfile(fpath,[fname fext]);
54 | end
55 | hgsave(fh, tmp_nam);
56 | fh = hgload(tmp_nam);
57 | delete(tmp_nam);
58 | end
59 | end
60 |
--------------------------------------------------------------------------------
/source_code/export_fig/crop_borders.m:
--------------------------------------------------------------------------------
1 | function [A, vA, vB, bb_rel] = crop_borders(A, bcol, padding, crop_amounts)
2 | %CROP_BORDERS Crop the borders of an image or stack of images
3 | %
4 | % [B, vA, vB, bb_rel] = crop_borders(A, bcol, [padding])
5 | %
6 | %IN:
7 | % A - HxWxCxN stack of images.
8 | % bcol - Cx1 background colour vector.
9 | % padding - scalar indicating how much padding to have in relation to
10 | % the cropped-image-size (0<=padding<=1). Default: 0
11 | % crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left]
12 | % where NaN/Inf indicate auto-cropping, 0 means no cropping,
13 | % and any other value mean cropping in pixel amounts.
14 | %
15 | %OUT:
16 | % B - JxKxCxN cropped stack of images.
17 | % vA - coordinates in A that contain the cropped image
18 | % vB - coordinates in B where the cropped version of A is placed
19 | % bb_rel - relative bounding box (used for eps-cropping)
20 |
21 | %{
22 | % 06/03/15: Improved image cropping thanks to Oscar Hartogensis
23 | % 08/06/15: Fixed issue #76: case of transparent figure bgcolor
24 | % 21/02/16: Enabled specifying non-automated crop amounts
25 | % 04/04/16: Fix per Luiz Carvalho for old Matlab releases
26 | % 23/10/16: Fixed issue #175: there used to be a 1px minimal padding in case of crop, now removed
27 | %}
28 |
29 | if nargin < 3
30 | padding = 0;
31 | end
32 | if nargin < 4
33 | crop_amounts = nan(1,4); % =auto-cropping
34 | end
35 | crop_amounts(end+1:4) = NaN; % fill missing values with NaN
36 |
37 | [h, w, c, n] = size(A);
38 | if isempty(bcol) % case of transparent bgcolor
39 | bcol = A(ceil(end/2),1,:,1);
40 | end
41 | if isscalar(bcol)
42 | bcol = bcol(ones(c, 1));
43 | end
44 |
45 | % Crop margin from left
46 | if ~isfinite(crop_amounts(4))
47 | bail = false;
48 | for l = 1:w
49 | for a = 1:c
50 | if ~all(col(A(:,l,a,:)) == bcol(a))
51 | bail = true;
52 | break;
53 | end
54 | end
55 | if bail
56 | break;
57 | end
58 | end
59 | else
60 | l = 1 + abs(crop_amounts(4));
61 | end
62 |
63 | % Crop margin from right
64 | if ~isfinite(crop_amounts(2))
65 | bcol = A(ceil(end/2),w,:,1);
66 | bail = false;
67 | for r = w:-1:l
68 | for a = 1:c
69 | if ~all(col(A(:,r,a,:)) == bcol(a))
70 | bail = true;
71 | break;
72 | end
73 | end
74 | if bail
75 | break;
76 | end
77 | end
78 | else
79 | r = w - abs(crop_amounts(2));
80 | end
81 |
82 | % Crop margin from top
83 | if ~isfinite(crop_amounts(1))
84 | bcol = A(1,ceil(end/2),:,1);
85 | bail = false;
86 | for t = 1:h
87 | for a = 1:c
88 | if ~all(col(A(t,:,a,:)) == bcol(a))
89 | bail = true;
90 | break;
91 | end
92 | end
93 | if bail
94 | break;
95 | end
96 | end
97 | else
98 | t = 1 + abs(crop_amounts(1));
99 | end
100 |
101 | % Crop margin from bottom
102 | bcol = A(h,ceil(end/2),:,1);
103 | if ~isfinite(crop_amounts(3))
104 | bail = false;
105 | for b = h:-1:t
106 | for a = 1:c
107 | if ~all(col(A(b,:,a,:)) == bcol(a))
108 | bail = true;
109 | break;
110 | end
111 | end
112 | if bail
113 | break;
114 | end
115 | end
116 | else
117 | b = h - abs(crop_amounts(3));
118 | end
119 |
120 | if padding == 0 % no padding
121 | % Issue #175: there used to be a 1px minimal padding in case of crop, now removed
122 | %{
123 | if ~isequal([t b l r], [1 h 1 w]) % Check if we're actually croppping
124 | padding = 1; % Leave one boundary pixel to avoid bleeding on resize
125 | bcol(:) = nan; % make the 1px padding transparent
126 | end
127 | %}
128 | elseif abs(padding) < 1 % pad value is a relative fraction of image size
129 | padding = sign(padding)*round(mean([b-t r-l])*abs(padding)); % ADJUST PADDING
130 | else % pad value is in units of 1/72" points
131 | padding = round(padding); % fix cases of non-integer pad value
132 | end
133 |
134 | if padding > 0 % extra padding
135 | % Create an empty image, containing the background color, that has the
136 | % cropped image size plus the padded border
137 | B = repmat(bcol,[(b-t)+1+padding*2,(r-l)+1+padding*2,1,n]); % Fix per Luiz Carvalho
138 | % vA - coordinates in A that contain the cropped image
139 | vA = [t b l r];
140 | % vB - coordinates in B where the cropped version of A will be placed
141 | vB = [padding+1, (b-t)+1+padding, padding+1, (r-l)+1+padding];
142 | % Place the original image in the empty image
143 | B(vB(1):vB(2), vB(3):vB(4), :, :) = A(vA(1):vA(2), vA(3):vA(4), :, :);
144 | A = B;
145 | else % extra cropping
146 | vA = [t-padding b+padding l-padding r+padding];
147 | A = A(vA(1):vA(2), vA(3):vA(4), :, :);
148 | vB = [NaN NaN NaN NaN];
149 | end
150 |
151 | % For EPS cropping, determine the relative BoundingBox - bb_rel
152 | bb_rel = [l-1 h-b-1 r+1 h-t+1]./[w h w h];
153 | end
154 |
155 | function A = col(A)
156 | A = A(:);
157 | end
158 |
--------------------------------------------------------------------------------
/source_code/export_fig/eps2pdf.m:
--------------------------------------------------------------------------------
1 | function eps2pdf(source, dest, crop, append, gray, quality, gs_options)
2 | %EPS2PDF Convert an eps file to pdf format using ghostscript
3 | %
4 | % Examples:
5 | % eps2pdf source dest
6 | % eps2pdf(source, dest, crop)
7 | % eps2pdf(source, dest, crop, append)
8 | % eps2pdf(source, dest, crop, append, gray)
9 | % eps2pdf(source, dest, crop, append, gray, quality)
10 | % eps2pdf(source, dest, crop, append, gray, quality, gs_options)
11 | %
12 | % This function converts an eps file to pdf format. The output can be
13 | % optionally cropped and also converted to grayscale. If the output pdf
14 | % file already exists then the eps file can optionally be appended as a new
15 | % page on the end of the eps file. The level of bitmap compression can also
16 | % optionally be set.
17 | %
18 | % This function requires that you have ghostscript installed on your
19 | % system. Ghostscript can be downloaded from: http://www.ghostscript.com
20 | %
21 | % Inputs:
22 | % source - filename of the source eps file to convert. The filename is
23 | % assumed to already have the extension ".eps".
24 | % dest - filename of the destination pdf file. The filename is assumed
25 | % to already have the extension ".pdf".
26 | % crop - boolean indicating whether to crop the borders off the pdf.
27 | % Default: true.
28 | % append - boolean indicating whether the eps should be appended to the
29 | % end of the pdf as a new page (if the pdf exists already).
30 | % Default: false.
31 | % gray - boolean indicating whether the output pdf should be grayscale
32 | % or not. Default: false.
33 | % quality - scalar indicating the level of image bitmap quality to
34 | % output. A larger value gives a higher quality. quality > 100
35 | % gives lossless output. Default: ghostscript prepress default.
36 | % gs_options - optional ghostscript options (e.g.: '-dNoOutputFonts'). If
37 | % multiple options are needed, enclose in call array: {'-a','-b'}
38 |
39 | % Copyright (C) Oliver Woodford 2009-2014, Yair Altman 2015-
40 |
41 | % Suggestion of appending pdf files provided by Matt C at:
42 | % http://www.mathworks.com/matlabcentral/fileexchange/23629
43 |
44 | % Thank you Fabio Viola for pointing out compression artifacts, leading to the quality setting.
45 | % Thank you Scott for pointing out the subsampling of very small images, which was fixed for lossless compression settings.
46 |
47 | % 09/12/11: Pass font path to ghostscript
48 | % 26/02/15: If temp dir is not writable, use the dest folder for temp destination files (Javier Paredes)
49 | % 28/02/15: Enable users to specify optional ghostscript options (issue #36)
50 | % 01/03/15: Upon GS error, retry without the -sFONTPATH= option (this might solve
51 | % some /findfont errors according to James Rankin, FEX Comment 23/01/15)
52 | % 23/06/15: Added extra debug info in case of ghostscript error; code indentation
53 | % 04/10/15: Suggest a workaround for issue #41 (missing font path; thanks Mariia Fedotenkova)
54 | % 22/02/16: Bug fix from latest release of this file (workaround for issue #41)
55 | % 20/03/17: Added informational message in case of GS croak (issue #186)
56 | % 16/01/18: Improved appending of multiple EPS files into single PDF (issue #233; thanks @shartjen)
57 | % 18/10/19: Workaround for GS 9.51+ .setpdfwrite removal problem (issue #285)
58 | % 18/10/19: Warn when ignoring GS fontpath or quality options; clarified error messages
59 | % 15/01/20: Added information about the GS/destination filepath in case of error (issue #294)
60 | % 20/01/20: Attempted fix for issue #285: unsupported patch transparency in some Ghostscript versions
61 | % 12/02/20: Improved fix for issue #285: add -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys)
62 |
63 | % Intialise the options string for ghostscript
64 | options = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="' dest '"'];
65 |
66 | % Set crop option
67 | if nargin < 3 || crop
68 | options = [options ' -dEPSCrop'];
69 | end
70 |
71 | % Set the font path
72 | fp = font_path();
73 | if ~isempty(fp)
74 | options = [options ' -sFONTPATH="' fp '"'];
75 | end
76 |
77 | % Set the grayscale option
78 | if nargin > 4 && gray
79 | options = [options ' -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray'];
80 | end
81 |
82 | % Set the bitmap quality
83 | qualityOptions = '';
84 | if nargin > 5 && ~isempty(quality)
85 | qualityOptions = ' -dAutoFilterColorImages=false -dAutoFilterGrayImages=false';
86 | if quality > 100
87 | qualityOptions = [qualityOptions ' -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode'];
88 | qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDownsampleThreshold 10 /GrayImageDownsampleThreshold 10 >> setdistillerparams"'];
89 | else
90 | qualityOptions = [qualityOptions ' -dColorImageFilter=/DCTEncode -dGrayImageFilter=/DCTEncode'];
91 | v = 1 + (quality < 80);
92 | quality = 1 - quality / 100;
93 | s = sprintf('<< /QFactor %.2f /Blend 1 /HSample [%d 1 1 %d] /VSample [%d 1 1 %d] >>', quality, v, v, v, v);
94 | qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDict ' s ' /GrayImageDict ' s ' >> setdistillerparams"'];
95 | end
96 | options = [options qualityOptions];
97 | end
98 |
99 | % Enable users to specify optional ghostscript options (issue #36)
100 | if nargin > 6 && ~isempty(gs_options)
101 | if iscell(gs_options)
102 | gs_options = sprintf(' %s',gs_options{:});
103 | elseif ~ischar(gs_options)
104 | error('gs_options input argument must be a string or cell-array of strings');
105 | else
106 | gs_options = [' ' gs_options];
107 | end
108 | options = [options gs_options];
109 | end
110 |
111 | % Check if the output file exists
112 | if nargin > 3 && append && exist(dest, 'file') == 2
113 | % File exists - append current figure to the end
114 | tmp_nam = [tempname '.pdf'];
115 | [fpath,fname,fext] = fileparts(tmp_nam);
116 | try
117 | % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
118 | fid = fopen(tmp_nam,'w');
119 | fwrite(fid,1);
120 | fclose(fid);
121 | delete(tmp_nam);
122 | catch
123 | % Temp dir is not writable, so use the dest folder
124 | fpath = fileparts(dest);
125 | tmp_nam = fullfile(fpath,[fname fext]);
126 | end
127 | % Copy the existing (dest) pdf file to temporary folder
128 | copyfile(dest, tmp_nam);
129 | % Produce an interim pdf of the source eps, rather than adding the eps directly (issue #233)
130 | ghostscript([options ' -f "' source '"']);
131 | [~,fname] = fileparts(tempname);
132 | tmp_nam2 = fullfile(fpath,[fname fext]); % ensure using a writable folder (not necessarily tempdir)
133 | copyfile(dest, tmp_nam2);
134 | % Add the existing pdf and interim pdf as inputs to ghostscript
135 | %options = [options ' -f "' tmp_nam '" "' source '"']; % append the source eps to dest pdf
136 | options = [options ' -f "' tmp_nam '" "' tmp_nam2 '"']; % append the interim pdf to dest pdf
137 | try
138 | % Convert to pdf using ghostscript
139 | [status, message] = ghostscript(options);
140 | catch me
141 | % Delete the intermediate files and rethrow the error
142 | delete(tmp_nam);
143 | delete(tmp_nam2);
144 | rethrow(me);
145 | end
146 | % Delete the intermediate (temporary) files
147 | delete(tmp_nam);
148 | delete(tmp_nam2);
149 | else
150 | % File doesn't exist or should be over-written
151 | % Add the source eps file as input to ghostscript
152 | options = [options ' -f "' source '"'];
153 | % Convert to pdf using ghostscript
154 | [status, message] = ghostscript(options);
155 | end
156 |
157 | % Check for error
158 | if status
159 | % Catch and correct undefined .setopacityalpha errors (issue #285)
160 | % (see explanation inside print2eps.m)
161 | if ~isempty(regexpi(message,'undefined in .setopacityalpha'))
162 | % First try with -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys)
163 | new_options = [options ' -dNOSAFER -dALLOWPSTRANSPARENCY'];
164 | [status, message] = ghostscript(new_options);
165 | if ~status % hurray! (no error)
166 | return
167 | elseif isempty(regexpi(message,'undefined in .setopacityalpha')) % still some other error
168 | options = new_options;
169 | else % we still get a .setopacityalpha error
170 | % Remove the transparency and retry
171 | fstrm = read_write_entire_textfile(source);
172 | fstrm = regexprep(fstrm, '0?\.\d+ .setopacityalpha \w+\n', '');
173 | read_write_entire_textfile(source, fstrm);
174 | [status, message] = ghostscript(options);
175 | if ~status % hurray! (no error)
176 | % Alert the user that transparency is not supported
177 | warning('export_fig:GS:quality','Export_fig Face/Edge alpha transparancy is ignored - not supported by your Ghostscript version')
178 | return
179 | end
180 | end
181 | end
182 |
183 | % Retry without the -sFONTPATH= option (this might solve some GS
184 | % /findfont errors according to James Rankin, FEX Comment 23/01/15)
185 | orig_options = options;
186 | if ~isempty(fp)
187 | options = regexprep(options, ' -sFONTPATH=[^ ]+ ',' ');
188 | [status, message] = ghostscript(options);
189 | if ~status % hurray! (no error)
190 | warning('export_fig:GS:fontpath','Export_fig font option is ignored - not supported by your Ghostscript version')
191 | return
192 | end
193 | end
194 |
195 | % Retry without quality options (may solve problems with GS 9.51+, issue #285)
196 | if ~isempty(qualityOptions)
197 | options = strrep(orig_options, qualityOptions, '');
198 | [status, message] = ghostscript(options);
199 | if ~status % hurray! (no error)
200 | warning('export_fig:GS:quality','Export_fig quality option is ignored - not supported by your Ghostscript version')
201 | return
202 | end
203 | end
204 |
205 | % Report error
206 | if isempty(message)
207 | error(['Unable to generate pdf. Ensure that the destination folder (' fileparts(dest) ') is writable.']);
208 | elseif ~isempty(strfind(message,'/typecheck in /findfont')) %#ok
209 | % Suggest a workaround for issue #41 (missing font path)
210 | font_name = strtrim(regexprep(message,'.*Operand stack:\s*(.*)\s*Execution.*','$1'));
211 | fprintf(2, 'Ghostscript error: could not find the following font(s): %s\n', font_name);
212 | %fpath = fileparts(mfilename('fullpath'));
213 | %gs_fonts_file = fullfile(fpath, '.ignore', 'gs_font_path.txt');
214 | [unused, gs_fonts_file] = user_string('gs_font_path'); %#ok
215 | fprintf(2, ' try to add the font''s folder to your %s file\n\n', gs_fonts_file);
216 | error('export_fig error');
217 | else
218 | gs_options = strtrim(gs_options);
219 | fprintf(2, '\nGhostscript error: ');
220 | msg = regexprep(message, '^Error: /([^\n]+).*', '$1');
221 | if ~isempty(msg) && ~strcmp(msg,message)
222 | fprintf(2,'%s',msg);
223 | end
224 | fprintf(2, '\n * perhaps %s is open by another application\n', dest);
225 | if ~isempty(gs_options)
226 | fprintf(2, ' * or maybe your Ghostscript version does not accept the extra "%s" option(s) that you requested\n', gs_options);
227 | end
228 | fprintf(2, ' * or maybe you have another gs executable in your system''s path\n\n');
229 | fprintf(2, 'Ghostscript path: %s\n', user_string('ghostscript'));
230 | fprintf(2, 'Ghostscript options: %s\n\n', orig_options);
231 | error(message);
232 | end
233 | end
234 | end
235 |
236 | % Function to return (and create, where necessary) the font path
237 | function fp = font_path()
238 | fp = user_string('gs_font_path');
239 | if ~isempty(fp)
240 | return
241 | end
242 | % Create the path
243 | % Start with the default path
244 | fp = getenv('GS_FONTPATH');
245 | % Add on the typical directories for a given OS
246 | if ispc
247 | if ~isempty(fp)
248 | fp = [fp ';'];
249 | end
250 | fp = [fp getenv('WINDIR') filesep 'Fonts'];
251 | else
252 | if ~isempty(fp)
253 | fp = [fp ':'];
254 | end
255 | fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype'];
256 | end
257 | user_string('gs_font_path', fp);
258 | end
259 |
--------------------------------------------------------------------------------
/source_code/export_fig/fix_lines.m:
--------------------------------------------------------------------------------
1 | %FIX_LINES Improves the line style of eps files generated by print
2 | %
3 | % Examples:
4 | % fix_lines fname
5 | % fix_lines fname fname2
6 | % fstrm_out = fixlines(fstrm_in)
7 | %
8 | % This function improves the style of lines in eps files generated by
9 | % MATLAB's print function, making them more similar to those seen on
10 | % screen. Grid lines are also changed from a dashed style to a dotted
11 | % style, for greater differentiation from dashed lines.
12 | %
13 | % The function also places embedded fonts after the postscript header, in
14 | % versions of MATLAB which place the fonts first (R2006b and earlier), in
15 | % order to allow programs such as Ghostscript to find the bounding box
16 | % information.
17 | %
18 | %IN:
19 | % fname - Name or path of source eps file.
20 | % fname2 - Name or path of destination eps file. Default: same as fname.
21 | % fstrm_in - File contents of a MATLAB-generated eps file.
22 | %
23 | %OUT:
24 | % fstrm_out - Contents of the eps file with line styles fixed.
25 |
26 | % Copyright: (C) Oliver Woodford, 2008-2014
27 |
28 | % The idea of editing the EPS file to change line styles comes from Jiro
29 | % Doke's FIXPSLINESTYLE (fex id: 17928)
30 | % The idea of changing dash length with line width came from comments on
31 | % fex id: 5743, but the implementation is mine :)
32 |
33 | % Thank you to Sylvain Favrot for bringing the embedded font/bounding box
34 | % interaction in older versions of MATLAB to my attention.
35 | % Thank you to D Ko for bringing an error with eps files with tiff previews
36 | % to my attention.
37 | % Thank you to Laurence K for suggesting the check to see if the file was
38 | % opened.
39 |
40 | % 01/03/15: Issue #20: warn users if using this function in HG2 (R2014b+)
41 | % 27/03/15: Fixed out of memory issue with enormous EPS files (generated by print() with OpenGL renderer), related to issue #39
42 |
43 | function fstrm = fix_lines(fstrm, fname2)
44 |
45 | % Issue #20: warn users if using this function in HG2 (R2014b+)
46 | if using_hg2
47 | warning('export_fig:hg2','The fix_lines function should not be used in this Matlab version.');
48 | end
49 |
50 | if nargout == 0 || nargin > 1
51 | if nargin < 2
52 | % Overwrite the input file
53 | fname2 = fstrm;
54 | end
55 | % Read in the file
56 | fstrm = read_write_entire_textfile(fstrm);
57 | end
58 |
59 | % Move any embedded fonts after the postscript header
60 | if strcmp(fstrm(1:15), '%!PS-AdobeFont-')
61 | % Find the start and end of the header
62 | ind = regexp(fstrm, '[\n\r]%!PS-Adobe-');
63 | [ind2, ind2] = regexp(fstrm, '[\n\r]%%EndComments[\n\r]+');
64 | % Put the header first
65 | if ~isempty(ind) && ~isempty(ind2) && ind(1) < ind2(1)
66 | fstrm = fstrm([ind(1)+1:ind2(1) 1:ind(1) ind2(1)+1:end]);
67 | end
68 | end
69 |
70 | % Make sure all line width commands come before the line style definitions,
71 | % so that dash lengths can be based on the correct widths
72 | % Find all line style sections
73 | ind = [regexp(fstrm, '[\n\r]SO[\n\r]'),... % This needs to be here even though it doesn't have dots/dashes!
74 | regexp(fstrm, '[\n\r]DO[\n\r]'),...
75 | regexp(fstrm, '[\n\r]DA[\n\r]'),...
76 | regexp(fstrm, '[\n\r]DD[\n\r]')];
77 | ind = sort(ind);
78 | % Find line width commands
79 | [ind2, ind3] = regexp(fstrm, '[\n\r]\d* w[\n\r]');
80 | % Go through each line style section and swap with any line width commands
81 | % near by
82 | b = 1;
83 | m = numel(ind);
84 | n = numel(ind2);
85 | for a = 1:m
86 | % Go forwards width commands until we pass the current line style
87 | while b <= n && ind2(b) < ind(a)
88 | b = b + 1;
89 | end
90 | if b > n
91 | % No more width commands
92 | break;
93 | end
94 | % Check we haven't gone past another line style (including SO!)
95 | if a < m && ind2(b) > ind(a+1)
96 | continue;
97 | end
98 | % Are the commands close enough to be confident we can swap them?
99 | if (ind2(b) - ind(a)) > 8
100 | continue;
101 | end
102 | % Move the line style command below the line width command
103 | fstrm(ind(a)+1:ind3(b)) = [fstrm(ind(a)+4:ind3(b)) fstrm(ind(a)+1:ind(a)+3)];
104 | b = b + 1;
105 | end
106 |
107 | % Find any grid line definitions and change to GR format
108 | % Find the DO sections again as they may have moved
109 | ind = int32(regexp(fstrm, '[\n\r]DO[\n\r]'));
110 | if ~isempty(ind)
111 | % Find all occurrences of what are believed to be axes and grid lines
112 | ind2 = int32(regexp(fstrm, '[\n\r] *\d* *\d* *mt *\d* *\d* *L[\n\r]'));
113 | if ~isempty(ind2)
114 | % Now see which DO sections come just before axes and grid lines
115 | ind2 = repmat(ind2', [1 numel(ind)]) - repmat(ind, [numel(ind2) 1]);
116 | ind2 = any(ind2 > 0 & ind2 < 12); % 12 chars seems about right
117 | ind = ind(ind2);
118 | % Change any regions we believe to be grid lines to GR
119 | fstrm(ind+1) = 'G';
120 | fstrm(ind+2) = 'R';
121 | end
122 | end
123 |
124 | % Define the new styles, including the new GR format
125 | % Dot and dash lengths have two parts: a constant amount plus a line width
126 | % variable amount. The constant amount comes after dpi2point, and the
127 | % variable amount comes after currentlinewidth. If you want to change
128 | % dot/dash lengths for a one particular line style only, edit the numbers
129 | % in the /DO (dotted lines), /DA (dashed lines), /DD (dot dash lines) and
130 | % /GR (grid lines) lines for the style you want to change.
131 | new_style = {'/dom { dpi2point 1 currentlinewidth 0.08 mul add mul mul } bdef',... % Dot length macro based on line width
132 | '/dam { dpi2point 2 currentlinewidth 0.04 mul add mul mul } bdef',... % Dash length macro based on line width
133 | '/SO { [] 0 setdash 0 setlinecap } bdef',... % Solid lines
134 | '/DO { [1 dom 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dotted lines
135 | '/DA { [4 dam 1.5 dam] 0 setdash 0 setlinecap } bdef',... % Dashed lines
136 | '/DD { [1 dom 1.2 dom 4 dam 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dot dash lines
137 | '/GR { [0 dpi2point mul 4 dpi2point mul] 0 setdash 1 setlinecap } bdef'}; % Grid lines - dot spacing remains constant
138 |
139 | % Construct the output
140 | % This is the original (memory-intensive) code:
141 | %first_sec = strfind(fstrm, '% line types:'); % Isolate line style definition section
142 | %[second_sec, remaining] = strtok(fstrm(first_sec+1:end), '/');
143 | %[remaining, remaining] = strtok(remaining, '%');
144 | %fstrm = [fstrm(1:first_sec) second_sec sprintf('%s\r', new_style{:}) remaining];
145 | fstrm = regexprep(fstrm,'(% line types:.+?)/.+?%',['$1',sprintf('%s\r',new_style{:}),'%']);
146 |
147 | % Write the output file
148 | if nargout == 0 || nargin > 1
149 | read_write_entire_textfile(fname2, fstrm);
150 | end
151 | end
152 |
--------------------------------------------------------------------------------
/source_code/export_fig/ghostscript.m:
--------------------------------------------------------------------------------
1 | function varargout = ghostscript(cmd)
2 | %GHOSTSCRIPT Calls a local GhostScript executable with the input command
3 | %
4 | % Example:
5 | % [status result] = ghostscript(cmd)
6 | %
7 | % Attempts to locate a ghostscript executable, finally asking the user to
8 | % specify the directory ghostcript was installed into. The resulting path
9 | % is stored for future reference.
10 | %
11 | % Once found, the executable is called with the input command string.
12 | %
13 | % This function requires a Ghostscript installation on your system.
14 | % You can download Ghostscript from http://ghostscript.com (Windows/Linux)
15 | % or http://pages.uoregon.edu/koch (MacOS).
16 | %
17 | % IN:
18 | % cmd - Command string to be passed into ghostscript.
19 | %
20 | % OUT:
21 | % status - 0 iff command ran without problem.
22 | % result - Output from ghostscript.
23 |
24 | % Copyright: Oliver Woodford, 2009-2015, Yair Altman 2015-
25 | %{
26 | % Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS.
27 | % Thanks to Nathan Childress for the fix to default location on 64-bit Windows systems.
28 | % 27/04/11 - Find 64-bit Ghostscript on Windows. Thanks to Paul Durack and
29 | % Shaun Kline for pointing out the issue
30 | % 04/05/11 - Thanks to David Chorlian for pointing out an alternative
31 | % location for gs on linux.
32 | % 12/12/12 - Add extra executable name on Windows. Thanks to Ratish
33 | % Punnoose for highlighting the issue.
34 | % 28/06/13 - Fix error using GS 9.07 in Linux. Many thanks to Jannick
35 | % Steinbring for proposing the fix.
36 | % 24/10/13 - Fix error using GS 9.07 in Linux. Many thanks to Johannes
37 | % for the fix.
38 | % 23/01/14 - Add full path to ghostscript.txt in warning. Thanks to Koen
39 | % Vermeer for raising the issue.
40 | % 27/02/15 - If Ghostscript croaks, display suggested workarounds
41 | % 30/03/15 - Improved performance by caching status of GS path check, if ok
42 | % 14/05/15 - Clarified warning message in case GS path could not be saved
43 | % 29/05/15 - Avoid cryptic error in case the ghostscipt path cannot be saved (issue #74)
44 | % 10/11/15 - Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX
45 | % 15/01/20 - Various message cleanups/fixes in case of errors
46 | %}
47 |
48 | try
49 | % Call ghostscript
50 | [varargout{1:nargout}] = system([gs_command(gs_path()) cmd]);
51 | catch err
52 | % Display possible workarounds for Ghostscript croaks
53 | url1 = 'https://github.com/altmany/export_fig/issues/12#issuecomment-61467998'; % issue #12
54 | url2 = 'https://github.com/altmany/export_fig/issues/20#issuecomment-63826270'; % issue #20
55 | hg2_str = ''; if using_hg2, hg2_str = ' or Matlab R2014a'; end
56 | fprintf(2, 'Ghostscript error. Rolling back to GS 9.10%s may possibly solve this:\n * %s ', hg2_str, hyperlink(url1));
57 | if using_hg2
58 | fprintf(2, '(GS 9.10)\n * %s (R2014a)', hyperlink(url2));
59 | end
60 | fprintf('\n\n');
61 | if ismac || isunix
62 | url3 = 'https://github.com/altmany/export_fig/issues/27'; % issue #27
63 | fprintf(2, 'Alternatively, this may possibly be due to a font path issue:\n * %s\n\n', hyperlink(url3));
64 | % issue #20
65 | % TODO: in Unix/Mac, find a way to automatically determine whether to use "export" (bash) or "setenv" (csh/tcsh)
66 | if isdeployed
67 | url = [mfilename '.m'];
68 | else
69 | fpath = which(mfilename);
70 | if isempty(fpath), fpath = [mfilename('fullpath') '.m']; end
71 | url = ['' fpath ''];
72 | end
73 | fprintf(2, 'Alternatively, if you are using csh, modify shell_cmd from "export ..." to "setenv ..."\nat the bottom of %s\n\n', url);
74 | end
75 | rethrow(err);
76 | end
77 | end
78 |
79 | function path_ = gs_path
80 | % Return a valid path
81 | % Start with the currently set path
82 | path_ = user_string('ghostscript');
83 | % Check the path works
84 | if check_gs_path(path_)
85 | return
86 | end
87 | % Check whether the binary is on the path
88 | if ispc
89 | bin = {'gswin32c.exe', 'gswin64c.exe', 'gs'};
90 | else
91 | bin = {'gs'};
92 | end
93 | for a = 1:numel(bin)
94 | path_ = bin{a};
95 | if check_store_gs_path(path_)
96 | return
97 | end
98 | end
99 | % Search the obvious places
100 | if ispc
101 | default_location = 'C:\Program Files\gs\';
102 | dir_list = dir(default_location);
103 | if isempty(dir_list)
104 | default_location = 'C:\Program Files (x86)\gs\'; % Possible location on 64-bit systems
105 | dir_list = dir(default_location);
106 | end
107 | executable = {'\bin\gswin32c.exe', '\bin\gswin64c.exe'};
108 | ver_num = 0;
109 | % If there are multiple versions, use the newest
110 | for a = 1:numel(dir_list)
111 | ver_num2 = sscanf(dir_list(a).name, 'gs%g');
112 | if ~isempty(ver_num2) && ver_num2 > ver_num
113 | for b = 1:numel(executable)
114 | path2 = [default_location dir_list(a).name executable{b}];
115 | if exist(path2, 'file') == 2
116 | path_ = path2;
117 | ver_num = ver_num2;
118 | end
119 | end
120 | end
121 | end
122 | if check_store_gs_path(path_)
123 | return
124 | end
125 | else
126 | executable = {'/usr/bin/gs', '/usr/local/bin/gs'};
127 | for a = 1:numel(executable)
128 | path_ = executable{a};
129 | if check_store_gs_path(path_)
130 | return
131 | end
132 | end
133 | end
134 | % Ask the user to enter the path
135 | while true
136 | if strncmp(computer, 'MAC', 3) % Is a Mac
137 | % Give separate warning as the uigetdir dialogue box doesn't have a
138 | % title on MacOS
139 | uiwait(warndlg('Ghostscript installation not found - please locate the program.', 'Ghostscript'))
140 | base = uigetdir('/', 'Ghostcript program location');
141 | else
142 | base = uigetdir('/', 'Ghostcript program not found - please locate it');
143 | end
144 | if isequal(base, 0)
145 | % User hit cancel or closed window
146 | break;
147 | end
148 | base = [base filesep]; %#ok
149 | bin_dir = {'', ['bin' filesep], ['lib' filesep]};
150 | for a = 1:numel(bin_dir)
151 | for b = 1:numel(bin)
152 | path_ = [base bin_dir{a} bin{b}];
153 | if exist(path_, 'file') == 2
154 | if check_store_gs_path(path_)
155 | return
156 | end
157 | end
158 | end
159 | end
160 | end
161 | if ismac
162 | url = 'http://pages.uoregon.edu/koch';
163 | else
164 | url = 'http://ghostscript.com';
165 | end
166 | error('Ghostscript:NotFound', 'Ghostscript not found. Have you installed it from %s ?', hyperlink(url));
167 | end
168 |
169 | function good = check_store_gs_path(path_)
170 | % Check the path is valid
171 | good = check_gs_path(path_);
172 | if ~good
173 | return
174 | end
175 | % Update the current default path to the path found
176 | if ~user_string('ghostscript', path_)
177 | %filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'ghostscript.txt');
178 | [unused, filename] = user_string('ghostscript'); %#ok
179 | warning('Ghostscript:path', 'Path to ghostscript installation could not be saved in %s (perhaps a permissions issue). You can manually create this file and set its contents to %s, to improve performance in future invocations (this warning is safe to ignore).', filename, path_);
180 | return
181 | end
182 | end
183 |
184 | function good = check_gs_path(path_)
185 | persistent isOk
186 | if isempty(path_)
187 | isOk = false;
188 | elseif ~isequal(isOk,true)
189 | % Check whether the path is valid
190 | [status, message] = system([gs_command(path_) '-h']); %#ok
191 | isOk = status == 0;
192 | end
193 | good = isOk;
194 | end
195 |
196 | function cmd = gs_command(path_)
197 | % Initialize any required system calls before calling ghostscript
198 | % TODO: in Unix/Mac, find a way to automatically determine whether to use "export" (bash) or "setenv" (csh/tcsh)
199 | shell_cmd = '';
200 | if isunix
201 | shell_cmd = 'export LD_LIBRARY_PATH=""; '; % Avoids an error on Linux with GS 9.07
202 | end
203 | if ismac
204 | shell_cmd = 'export DYLD_LIBRARY_PATH=""; '; % Avoids an error on Mac with GS 9.07
205 | end
206 | % Construct the command string
207 | cmd = sprintf('%s"%s" ', shell_cmd, path_);
208 | end
209 |
--------------------------------------------------------------------------------
/source_code/export_fig/hyperlink.m:
--------------------------------------------------------------------------------
1 | function str = hyperlink(url, label, msg)
2 | %HYPERLINK create a string that is displayable as hyperlink in Matlab console
3 | %
4 | % Usage examples:
5 | % fprintf('Search on %s\n', hyperlink('http://google.com','Google'));
6 | % fprintf(hyperlink('http://google.com','Google','Search on Google\n'));
7 | %
8 | % HYPERLINK converts the specified URL and text label into a string that is
9 | % displayed as a hyperlink in the Matlab console (Command Window).
10 | % In a deployed (compiled) program, the URL and text label (if different
11 | % from the URL) are displayed in a non-hyperlinked plain-text manner.
12 | % If the optional 3rd input argument (msg) is specified, then all instances of
13 | % the specified label within msg will be handled as above (hyperlinked etc.)
14 | %
15 | % IN:
16 | % url - (mandatory) URL of webpage or Matlab command (e.g., 'matlab:which(...')
17 | % label - (optional) text label of the hyperlink. Default: url
18 | % msg - (optional) string in which all label instances should be hyperlinked
19 | %
20 | % OUT:
21 | % str - string output
22 |
23 | % Copyright: Yair Altman 2020-
24 | %{
25 | % 15/01/20 - Initial version
26 | %}
27 |
28 | error(nargchk(1,3,nargin)); %#ok narginchk is only available in R2011b+
29 | if nargin > 2 % msg was specified
30 | % replace all instances of label within msg with corresponding hyperlink
31 | str = strrep(msg, label, hyperlink(url,label));
32 | return
33 | end
34 | if nargin < 2, label = url; end
35 | isWebpage = strncmpi(url,'http',4);
36 |
37 | % Only hyperlink in interactive Matlab sessions, not in a deployed program
38 | if ~isdeployed % interactive Matlab session
39 | if isWebpage % open in a web browser
40 | str = ['' label ''];
41 | else % Matlab command e.g. 'matlab:which(...'
42 | str = ['' label ''];
43 | end
44 | else % deployed (compiled)
45 | if isWebpage && ~strcmp(label,url) % display label next to url
46 | str = [label ' (' url ')'];
47 | elseif isWebpage % text==url - display only the url
48 | str = url;
49 | else % Matlab command (not a webpage) - just display the label
50 | str = label;
51 | end
52 | end
53 | end
54 |
--------------------------------------------------------------------------------
/source_code/export_fig/im2gif.m:
--------------------------------------------------------------------------------
1 | %IM2GIF Convert a multiframe image to an animated GIF file
2 | %
3 | % Examples:
4 | % im2gif infile
5 | % im2gif infile outfile
6 | % im2gif(A, outfile)
7 | % im2gif(..., '-nocrop')
8 | % im2gif(..., '-nodither')
9 | % im2gif(..., '-ncolors', n)
10 | % im2gif(..., '-loops', n)
11 | % im2gif(..., '-delay', n)
12 | %
13 | % This function converts a multiframe image to an animated GIF.
14 | %
15 | % To create an animation from a series of figures, export to a multiframe
16 | % TIFF file using export_fig, then convert to a GIF, as follows:
17 | %
18 | % for a = 2 .^ (3:6)
19 | % peaks(a);
20 | % export_fig test.tif -nocrop -append
21 | % end
22 | % im2gif('test.tif', '-delay', 0.5);
23 | %
24 | %IN:
25 | % infile - string containing the name of the input image.
26 | % outfile - string containing the name of the output image (must have the
27 | % .gif extension). Default: infile, with .gif extension.
28 | % A - HxWxCxN array of input images, stacked along fourth dimension, to
29 | % be converted to gif.
30 | % -nocrop - option indicating that the borders of the output are not to
31 | % be cropped.
32 | % -nodither - option indicating that dithering is not to be used when
33 | % converting the image.
34 | % -ncolors - option pair, the value of which indicates the maximum number
35 | % of colors the GIF can have. This can also be a quantization
36 | % tolerance, between 0 and 1. Default/maximum: 256.
37 | % -loops - option pair, the value of which gives the number of times the
38 | % animation is to be looped. Default: 65535.
39 | % -delay - option pair, the value of which gives the time, in seconds,
40 | % between frames. Default: 1/15.
41 |
42 | % Copyright (C) Oliver Woodford 2011
43 |
44 | %{
45 | % 14/02/18: Merged issue #235: reduced memory usage, improved performance (thanks to @numb7rs)
46 | % 30/11/19: Merged issue #288: Fix im2gif.m for greyscale TIFF images (thanks @Blackbelt1221)
47 | %}
48 |
49 | function im2gif(A, varargin)
50 |
51 | % Parse the input arguments
52 | [A, options] = parse_args(A, varargin{:});
53 |
54 | if options.crop ~= 0
55 | % Crop
56 | A = crop_borders(A, A(ceil(end/2),1,:,1));
57 | end
58 |
59 | % Convert to indexed image
60 | [h, w, c, n] = size(A);
61 |
62 | % Issue #235: Using unique(A,'rows') on the whole image stack at once causes
63 | % massive memory usage when dealing with large images (at least on Matlab 2017b).
64 | % Running unique(...) on individual frames, then again on the results drastically
65 | % reduces the memory usage & slightly improves the execution time (@numb7rs).
66 | uns = cell(1,size(A,4));
67 | for nn=1:size(A,4)
68 | uns{nn}=unique(reshape(A(:,:,:,nn), h*w, c),'rows');
69 | end
70 | map=unique(cell2mat(uns'),'rows');
71 |
72 | A = reshape(permute(A, [1 2 4 3]), h, w*n, c);
73 |
74 | if size(map, 1) > 256
75 | dither_str = {'dither', 'nodither'};
76 | dither_str = dither_str{1+(options.dither==0)};
77 | if options.ncolors <= 1
78 | [B, map] = rgb2ind(A, options.ncolors, dither_str);
79 | if size(map, 1) > 256
80 | [B, map] = rgb2ind(A, 256, dither_str);
81 | end
82 | else
83 | [B, map] = rgb2ind(A, min(round(options.ncolors), 256), dither_str);
84 | end
85 | else
86 | if max(map(:)) > 1
87 | map = double(map) / 255;
88 | A = double(A) / 255;
89 | end
90 | B = rgb2ind(im2double(A), map);
91 | end
92 | B = reshape(B, h, w, 1, n);
93 |
94 | % Bug fix to rgb2ind
95 | map(B(1)+1,:) = im2double(A(1,1,:));
96 |
97 | % Save as a gif
98 | imwrite(B, map, options.outfile, 'LoopCount', round(options.loops(1)), 'DelayTime', options.delay);
99 | end
100 |
101 | %% Parse the input arguments
102 | function [A, options] = parse_args(A, varargin)
103 | % Set the defaults
104 | options = struct('outfile', '', ...
105 | 'dither', true, ...
106 | 'crop', true, ...
107 | 'ncolors', 256, ...
108 | 'loops', 65535, ...
109 | 'delay', 1/15);
110 |
111 | % Go through the arguments
112 | a = 0;
113 | n = numel(varargin);
114 | while a < n
115 | a = a + 1;
116 | if ischar(varargin{a}) && ~isempty(varargin{a})
117 | if varargin{a}(1) == '-'
118 | opt = lower(varargin{a}(2:end));
119 | switch opt
120 | case 'nocrop'
121 | options.crop = false;
122 | case 'nodither'
123 | options.dither = false;
124 | otherwise
125 | if ~isfield(options, opt)
126 | error('Option %s not recognized', varargin{a});
127 | end
128 | a = a + 1;
129 | if ischar(varargin{a}) && ~ischar(options.(opt))
130 | options.(opt) = str2double(varargin{a});
131 | else
132 | options.(opt) = varargin{a};
133 | end
134 | end
135 | else
136 | options.outfile = varargin{a};
137 | end
138 | end
139 | end
140 |
141 | if isempty(options.outfile)
142 | if ~ischar(A)
143 | error('No output filename given.');
144 | end
145 | % Generate the output filename from the input filename
146 | [path, outfile] = fileparts(A);
147 | options.outfile = fullfile(path, [outfile '.gif']);
148 | end
149 |
150 | if ischar(A)
151 | % Read in the image
152 | A = imread_rgb(A);
153 | end
154 | end
155 |
156 | %% Read image to uint8 rgb array
157 | function [A, alpha] = imread_rgb(name)
158 | % Get file info
159 | info = imfinfo(name);
160 | % Special case formats
161 | switch lower(info(1).Format)
162 | case 'gif'
163 | [A, map] = imread(name, 'frames', 'all');
164 | if ~isempty(map)
165 | map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
166 | A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
167 | A = permute(A, [1 2 5 4 3]);
168 | end
169 | case {'tif', 'tiff'}
170 | A = cell(numel(info), 1);
171 | for a = 1:numel(A)
172 | [A{a}, map] = imread(name, 'Index', a, 'Info', info);
173 | if ~isempty(map)
174 | map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
175 | A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
176 | end
177 | if size(A{a}, 3) == 4
178 | % TIFF in CMYK colourspace - convert to RGB
179 | if isfloat(A{a})
180 | A{a} = A{a} * 255;
181 | else
182 | A{a} = single(A{a});
183 | end
184 | A{a} = 255 - A{a};
185 | A{a}(:,:,4) = A{a}(:,:,4) / 255;
186 | A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4]));
187 | elseif size(A{a}, 3) < 3 %Check whether TIFF has been read in as greyscale
188 | %Convert from greyscale to RGB colorspace (issue #288)
189 | A{a} = cat(3, A{a}, A{a}, A{a});
190 | end
191 | end
192 | A = cat(4, A{:});
193 | otherwise
194 | [A, map, alpha] = imread(name);
195 | A = A(:,:,:,1); % Keep only first frame of multi-frame files
196 | if ~isempty(map)
197 | map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
198 | A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
199 | elseif size(A, 3) == 4
200 | % Assume 4th channel is an alpha matte
201 | alpha = A(:,:,4);
202 | A = A(:,:,1:3);
203 | end
204 | end
205 | end
206 |
--------------------------------------------------------------------------------
/source_code/export_fig/isolate_axes.m:
--------------------------------------------------------------------------------
1 | function fh = isolate_axes(ah, vis)
2 | %ISOLATE_AXES Isolate the specified axes in a figure on their own
3 | %
4 | % Examples:
5 | % fh = isolate_axes(ah)
6 | % fh = isolate_axes(ah, vis)
7 | %
8 | % This function will create a new figure containing the axes/uipanels
9 | % specified, and also their associated legends and colorbars. The objects
10 | % specified must all be in the same figure, but they will generally only be
11 | % a subset of the objects in the figure.
12 | %
13 | % IN:
14 | % ah - An array of axes and uipanel handles, which must come from the
15 | % same figure.
16 | % vis - A boolean indicating whether the new figure should be visible.
17 | % Default: false.
18 | %
19 | % OUT:
20 | % fh - The handle of the created figure.
21 |
22 | % Copyright (C) Oliver Woodford 2011-2013
23 |
24 | % Thank you to Rosella Blatt for reporting a bug to do with axes in GUIs
25 | % 16/03/12: Moved copyfig to its own function. Thanks to Bob Fratantonio
26 | % for pointing out that the function is also used in export_fig.m
27 | % 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it
28 | % 08/10/13: Bug fix to allchildren suggested by Will Grant (many thanks!)
29 | % 05/12/13: Bug fix to axes having different units. Thanks to Remington Reid for reporting
30 | % 21/04/15: Bug fix for exporting uipanels with legend/colorbar on HG1 (reported by Alvaro
31 | % on FEX page as a comment on 24-Apr-2014); standardized indentation & help section
32 | % 22/04/15: Bug fix: legends and colorbars were not exported when exporting axes handle in HG2
33 |
34 | % Make sure we have an array of handles
35 | if ~all(ishandle(ah))
36 | error('ah must be an array of handles');
37 | end
38 | % Check that the handles are all for axes or uipanels, and are all in the same figure
39 | fh = ancestor(ah(1), 'figure');
40 | nAx = numel(ah);
41 | for a = 1:nAx
42 | if ~ismember(get(ah(a), 'Type'), {'axes', 'uipanel'})
43 | error('All handles must be axes or uipanel handles.');
44 | end
45 | if ~isequal(ancestor(ah(a), 'figure'), fh)
46 | error('Axes must all come from the same figure.');
47 | end
48 | end
49 | % Tag the objects so we can find them in the copy
50 | old_tag = get(ah, 'Tag');
51 | if nAx == 1
52 | old_tag = {old_tag};
53 | end
54 | set(ah, 'Tag', 'ObjectToCopy');
55 | % Create a new figure exactly the same as the old one
56 | fh = copyfig(fh); %copyobj(fh, 0);
57 | if nargin < 2 || ~vis
58 | set(fh, 'Visible', 'off');
59 | end
60 | % Reset the object tags
61 | for a = 1:nAx
62 | set(ah(a), 'Tag', old_tag{a});
63 | end
64 | % Find the objects to save
65 | ah = findall(fh, 'Tag', 'ObjectToCopy');
66 | if numel(ah) ~= nAx
67 | close(fh);
68 | error('Incorrect number of objects found.');
69 | end
70 | % Set the axes tags to what they should be
71 | for a = 1:nAx
72 | set(ah(a), 'Tag', old_tag{a});
73 | end
74 | % Keep any legends and colorbars which overlap the subplots
75 | % Note: in HG1 these are axes objects; in HG2 they are separate objects, therefore we
76 | % don't test for the type, only the tag (hopefully nobody but Matlab uses them!)
77 | lh = findall(fh, 'Tag', 'legend', '-or', 'Tag', 'Colorbar');
78 | nLeg = numel(lh);
79 | if nLeg > 0
80 | set([ah(:); lh(:)], 'Units', 'normalized');
81 | try
82 | ax_pos = get(ah, 'OuterPosition'); % axes and figures have the OuterPosition property
83 | catch
84 | ax_pos = get(ah, 'Position'); % uipanels only have Position, not OuterPosition
85 | end
86 | if nAx > 1
87 | ax_pos = cell2mat(ax_pos(:));
88 | end
89 | ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2);
90 | try
91 | leg_pos = get(lh, 'OuterPosition');
92 | catch
93 | leg_pos = get(lh, 'Position'); % No OuterPosition in HG2, only in HG1
94 | end
95 | if nLeg > 1;
96 | leg_pos = cell2mat(leg_pos);
97 | end
98 | leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2);
99 | ax_pos = shiftdim(ax_pos, -1);
100 | % Overlap test
101 | M = bsxfun(@lt, leg_pos(:,1), ax_pos(:,:,3)) & ...
102 | bsxfun(@lt, leg_pos(:,2), ax_pos(:,:,4)) & ...
103 | bsxfun(@gt, leg_pos(:,3), ax_pos(:,:,1)) & ...
104 | bsxfun(@gt, leg_pos(:,4), ax_pos(:,:,2));
105 | ah = [ah; lh(any(M, 2))];
106 | end
107 | % Get all the objects in the figure
108 | axs = findall(fh);
109 | % Delete everything except for the input objects and associated items
110 | delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)])));
111 | end
112 |
113 | function ah = allchildren(ah)
114 | ah = findall(ah);
115 | if iscell(ah)
116 | ah = cell2mat(ah);
117 | end
118 | ah = ah(:);
119 | end
120 |
121 | function ph = allancestors(ah)
122 | ph = [];
123 | for a = 1:numel(ah)
124 | h = get(ah(a), 'parent');
125 | while h ~= 0
126 | ph = [ph; h];
127 | h = get(h, 'parent');
128 | end
129 | end
130 | end
131 |
--------------------------------------------------------------------------------
/source_code/export_fig/pdf2eps.m:
--------------------------------------------------------------------------------
1 | %PDF2EPS Convert a pdf file to eps format using pdftops
2 | %
3 | % Examples:
4 | % pdf2eps source dest
5 | %
6 | % This function converts a pdf file to eps format.
7 | %
8 | % This function requires that you have pdftops, from the Xpdf suite of
9 | % functions, installed on your system. This can be downloaded from:
10 | % http://xpdfreader.com
11 | %
12 | % Inputs:
13 | % source - filename of the source pdf file to convert. The filename is
14 | % assumed to already have the extension ".pdf".
15 | % dest - filename of the destination eps file. The filename is assumed to
16 | % already have the extension ".eps".
17 |
18 | % Copyright (C) Oliver Woodford 2009-2010, Yair Altman 2015-
19 |
20 | % Thanks to Aldebaro Klautau for reporting a bug when saving to
21 | % non-existant directories.
22 |
23 | % 22/09/2018 - Xpdf website changed to xpdfreader.com
24 |
25 | function pdf2eps(source, dest)
26 | % Construct the options string for pdftops
27 | options = ['-q -paper match -eps -level2 "' source '" "' dest '"'];
28 |
29 | % Convert to eps using pdftops
30 | [status, message] = pdftops(options);
31 |
32 | % Check for error
33 | if status
34 | % Report error
35 | if isempty(message)
36 | error('Unable to generate eps. Check destination directory is writable.');
37 | else
38 | error(message);
39 | end
40 | end
41 |
42 | % Fix the DSC error created by pdftops
43 | fid = fopen(dest, 'r+');
44 | if fid == -1
45 | % Cannot open the file
46 | return
47 | end
48 | fgetl(fid); % Get the first line
49 | str = fgetl(fid); % Get the second line
50 | if strcmp(str(1:min(13, end)), '% Produced by')
51 | fseek(fid, -numel(str)-1, 'cof');
52 | fwrite(fid, '%'); % Turn ' ' into '%'
53 | end
54 | fclose(fid);
55 | end
56 |
--------------------------------------------------------------------------------
/source_code/export_fig/pdftops.m:
--------------------------------------------------------------------------------
1 | function varargout = pdftops(cmd)
2 | %PDFTOPS Calls a local pdftops executable with the input command
3 | %
4 | % Example:
5 | % [status result] = pdftops(cmd)
6 | %
7 | % Attempts to locate a pdftops executable, finally asking the user to
8 | % specify the directory pdftops was installed into. The resulting path is
9 | % stored for future reference.
10 | %
11 | % Once found, the executable is called with the input command string.
12 | %
13 | % This function requires that you have pdftops (from the Xpdf package)
14 | % installed on your system. You can download this from: http://xpdfreader.com
15 | %
16 | % IN:
17 | % cmd - Command string to be passed into pdftops (e.g. '-help').
18 | %
19 | % OUT:
20 | % status - 0 iff command ran without problem.
21 | % result - Output from pdftops.
22 |
23 | % Copyright: Oliver Woodford, 2009-2010
24 |
25 | % Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS.
26 | % Thanks to Christoph Hertel for pointing out a bug in check_xpdf_path under linux.
27 | % 23/01/2014 - Add full path to pdftops.txt in warning.
28 | % 27/05/2015 - Fixed alert in case of missing pdftops; fixed code indentation
29 | % 02/05/2016 - Added possible error explanation suggested by Michael Pacer (issue #137)
30 | % 02/05/2016 - Search additional possible paths suggested by Jonas Stein (issue #147)
31 | % 03/05/2016 - Display the specific error message if pdftops fails for some reason (issue #148)
32 | % 22/09/2018 - Xpdf website changed to xpdfreader.com; improved popup logic
33 | % 03/02/2019 - Fixed one-off 'pdftops not found' error after install (Mac/Linux) (issue #266)
34 | % 15/01/2020 - Fixed reported path of pdftops.txt file in case of error; added warning ID
35 | % 23/07/2020 - Fixed issue #311 (confusion regarding Xpdf-tools download/installation); silent check of pdftops installation in case no input arg specified
36 |
37 | % If no command parameter specified, just check pdftops installation and bail out
38 | if nargin < 1
39 | xpdf_path(); % this will error if pdftops is not found
40 | return % silent bail-out if pdftops was successfully located
41 | end
42 |
43 | % Call pdftops
44 | [varargout{1:nargout}] = system([xpdf_command(xpdf_path()) cmd]);
45 | end
46 |
47 | function path_ = xpdf_path
48 | % Return a valid path
49 | % Start with the currently set path
50 | path_ = user_string('pdftops');
51 | % Check the path works
52 | if check_xpdf_path(path_)
53 | return
54 | end
55 | % Check whether the binary is on the path
56 | if ispc
57 | bin = 'pdftops.exe';
58 | else
59 | bin = 'pdftops';
60 | end
61 | if check_store_xpdf_path(bin)
62 | path_ = bin;
63 | return
64 | end
65 | % Search the obvious places
66 | if ispc
67 | paths = {'C:\Program Files\xpdf\pdftops.exe', 'C:\Program Files (x86)\xpdf\pdftops.exe'};
68 | else
69 | paths = {'/usr/bin/pdftops', '/usr/local/bin/pdftops'};
70 | end
71 | for a = 1:numel(paths)
72 | path_ = paths{a};
73 | if check_store_xpdf_path(path_)
74 | return
75 | end
76 | end
77 |
78 | % Ask the user to enter the path
79 | errMsg1 = 'Pdftops utility not found. Please locate the program, or install xpdf-tools from ';
80 | url1 = 'http://xpdfreader.com/download.html'; %='http://foolabs.com/xpdf';
81 | fprintf(2, '%s%s ("Xpdf command line tools" section)\n', errMsg1, hyperlink(url1));
82 | errMsg1 = [errMsg1 url1];
83 | %if strncmp(computer,'MAC',3) % Is a Mac
84 | % % Give separate warning as the MacOS uigetdir dialogue box doesn't have a title
85 | % uiwait(warndlg(errMsg1))
86 | %end
87 |
88 | % Provide an alternative possible explanation as per issue #137
89 | errMsg2 = 'If pdftops is installed, maybe Matlab is shaddowing it, as described in ';
90 | url2 = 'https://github.com/altmany/export_fig/issues/137';
91 | fprintf(2, '%s%s\n', errMsg2, hyperlink(url2,'issue #137'));
92 | errMsg2 = [errMsg2 url2];
93 |
94 | % Provide an alternative possible explanation as per issue #311
95 | errMsg3 = 'Or perhaps you installed XpdfReader but not xpdf-tools, as described in ';
96 | url3 = 'https://github.com/altmany/export_fig/issues/311';
97 | fprintf(2, '%s%s\n', errMsg3, hyperlink(url3,'issue #311'));
98 | errMsg3 = [errMsg3 url3];
99 |
100 | state = 1;
101 | while 1
102 | if state
103 | option1 = 'Install pdftops';
104 | else
105 | option1 = 'Issue #137';
106 | end
107 | answer = questdlg({errMsg1,'',errMsg2,'',errMsg3},'Pdftops error',option1,'Locate pdftops','Cancel','Cancel');
108 | drawnow; % prevent a Matlab hang: http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem
109 | switch answer
110 | case 'Install pdftops'
111 | web('-browser',url1);
112 | state = 0;
113 | case 'Issue #137'
114 | web('-browser',url2);
115 | state = 1;
116 | case 'Locate pdftops'
117 | base = uigetdir('/', errMsg1);
118 | if isequal(base, 0)
119 | % User hit cancel or closed window
120 | break
121 | end
122 | base = [base filesep]; %#ok
123 | bin_dir = {'', ['bin' filesep], ['lib' filesep]};
124 | for a = 1:numel(bin_dir)
125 | path_ = [base bin_dir{a} bin];
126 | if exist(path_, 'file') == 2
127 | break
128 | end
129 | end
130 | if check_store_xpdf_path(path_)
131 | return
132 | end
133 |
134 | otherwise % User hit Cancel or closed window
135 | break
136 | end
137 | end
138 | error('pdftops executable not found.');
139 | end
140 |
141 | function good = check_store_xpdf_path(path_)
142 | % Check the path is valid
143 | good = check_xpdf_path(path_);
144 | if ~good
145 | return
146 | end
147 | % Update the current default path to the path found
148 | if ~user_string('pdftops', path_)
149 | %filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'pdftops.txt');
150 | [unused, filename] = user_string('pdftops'); %#ok
151 | warning('export_fig:pdftops','Path to pdftops executable could not be saved. Enter it manually in %s.', filename);
152 | return
153 | end
154 | end
155 |
156 | function good = check_xpdf_path(path_)
157 | % Check the path is valid
158 | [good, message] = system([xpdf_command(path_) '-h']); %#ok
159 | % system returns good = 1 even when the command runs
160 | % Look for something distinct in the help text
161 | good = ~isempty(strfind(message, 'PostScript')); %#ok
162 |
163 | % Display the error message if the pdftops executable exists but fails for some reason
164 | % Note: on Mac/Linux, exist('pdftops','file') will always return 2 due to pdftops.m => check for '/','.' (issue #266)
165 | if ~good && exist(path_,'file') && ~isempty(regexp(path_,'[/.]')) %#ok % file exists but generates an error
166 | fprintf('Error running %s:\n', path_);
167 | fprintf(2,'%s\n\n',message);
168 | end
169 | end
170 |
171 | function cmd = xpdf_command(path_)
172 | % Initialize any required system calls before calling ghostscript
173 | % TODO: in Unix/Mac, find a way to determine whether to use "export" (bash) or "setenv" (csh/tcsh)
174 | shell_cmd = '';
175 | if isunix
176 | % Avoids an error on Linux with outdated MATLAB lib files
177 | % R20XXa/bin/glnxa64/libtiff.so.X
178 | % R20XXa/sys/os/glnxa64/libstdc++.so.X
179 | shell_cmd = 'export LD_LIBRARY_PATH=""; ';
180 | end
181 | if ismac
182 | shell_cmd = 'export DYLD_LIBRARY_PATH=""; ';
183 | end
184 | % Construct the command string
185 | cmd = sprintf('%s"%s" ', shell_cmd, path_);
186 | end
187 |
--------------------------------------------------------------------------------
/source_code/export_fig/print2array.m:
--------------------------------------------------------------------------------
1 | function [A, bcol, alpha] = print2array(fig, res, renderer, gs_options)
2 | %PRINT2ARRAY Exports a figure to a bitmap RGB image array
3 | %
4 | % Examples:
5 | % A = print2array
6 | % A = print2array(figure_handle)
7 | % A = print2array(figure_handle, resolution)
8 | % A = print2array(figure_handle, resolution, renderer)
9 | % A = print2array(figure_handle, resolution, renderer, gs_options)
10 | % [A, bcol, alpha] = print2array(...)
11 | %
12 | % This function outputs a bitmap image of a figure, at the desired resolution.
13 | %
14 | % When resolution==1, fast Java screen-capture is attempted first.
15 | % If the Java screen-capture fails or if resolution~=1, the builtin print()
16 | % function is used to create a temp TIF file, which is then loaded and reported.
17 | % If this fails, print() is used to create a temp EPS file which is converted to
18 | % a TIF file using Ghostcript (http://www.ghostscript.com), loaded and reported.
19 | %
20 | % Inputs:
21 | % figure_handle - The handle of the figure to be exported. Default: gcf.
22 | % resolution - Output resolution as a factor of screen resolution. Default: 1
23 | % Note: resolution ~= 1 uses a slow print to/from image file
24 | % renderer - The renderer to be used by print() function. Default: '-opengl'
25 | % Note: only used when resolution ~= 1
26 | % gs_options - optional ghostscript parameters (e.g.: '-dNoOutputFonts').
27 | % Enclose multiple options in a cell array, e.g. {'-a','-b'}
28 | % Note: only used when resolution ~= 1 and basic print() fails
29 | %
30 | % Outputs:
31 | % A - MxNx3 uint8 bitmap image of the figure (MxN pixels x 3 RGB values)
32 | % bcol - 1x3 uint8 vector of the background RGB color
33 | % alpha - MxN uint8 array of alpha values (between 0=transparent, 255=opaque)
34 |
35 | % Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015-
36 | %{
37 | % 05/09/11: Set EraseModes to normal when using opengl or zbuffer
38 | % renderers. Thanks to Pawel Kocieniewski for reporting the issue.
39 | % 21/09/11: Bug fix: unit8 -> uint8! Thanks to Tobias Lamour for reporting it.
40 | % 14/11/11: Bug fix: stop using hardcopy(), as it interfered with figure size
41 | % and erasemode settings. Makes it a bit slower, but more reliable.
42 | % Thanks to Phil Trinh and Meelis Lootus for reporting the issues.
43 | % 09/12/11: Pass font path to ghostscript.
44 | % 27/01/12: Bug fix affecting painters rendering tall figures. Thanks to
45 | % Ken Campbell for reporting it.
46 | % 03/04/12: Bug fix to median input. Thanks to Andy Matthews for reporting it.
47 | % 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts for
48 | % reporting the issue.
49 | % 26/02/15: If temp dir is not writable, use the current folder for temp
50 | % EPS/TIF files (Javier Paredes)
51 | % 27/02/15: Display suggested workarounds to internal print() error (issue #16)
52 | % 28/02/15: Enable users to specify optional ghostscript options (issue #36)
53 | % 10/03/15: Fixed minor warning reported by Paul Soderlind; fixed code indentation
54 | % 28/05/15: Fixed issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() func)
55 | % 07/07/15: Fixed issue #83: use numeric handles in HG1
56 | % 11/12/16: Fixed cropping issue reported by Harry D.
57 | % 29/09/18: Fixed issue #254: error in print2array>read_tif_img
58 | % 22/03/20: Alert if ghostscript.m is required but not found on Matlab path
59 | % 24/05/20: Significant performance speedup; added alpha values (where possible)
60 | % 07/07/20: Fixed issue #308: bug in R2019a and earlier
61 | % 07/10/20: Use JavaFrame_I where possible, to avoid evoking a JavaFrame warning
62 | %}
63 |
64 | % Generate default input arguments, if needed
65 | if nargin < 1, fig = gcf; end
66 | if nargin < 2, res = 1; end
67 |
68 | % Get the figure size in pixels
69 | old_mode = get(fig, 'Units');
70 | set(fig, 'Units', 'pixels');
71 | px = get(fig, 'Position');
72 | set(fig, 'Units', old_mode);
73 |
74 | % Retrieve the background colour
75 | bcol = get(fig, 'Color');
76 | try
77 | % Try a direct Java screen-capture first - *MUCH* faster than print() to file
78 | % Note: we could also use A=matlab.graphics.internal.getframeWithDecorations(fig,false) but it (1) returns no alpha and (2) does not exist in older Matlabs
79 | if res == 1
80 | [A, alpha] = getJavaImage(fig);
81 | else
82 | error('magnify/downscale via print() to image file and then import');
83 | end
84 | catch err %#ok
85 | % Warn if output is large
86 | npx = prod(px(3:4)*res)/1e6;
87 | if npx > 30
88 | % 30M pixels or larger!
89 | warning('MATLAB:LargeImage', 'print2array generating a %.1fM pixel image. This could be slow and might also cause memory problems.', npx);
90 | end
91 | % Set the resolution parameter
92 | res_str = ['-r' num2str(ceil(get(0, 'ScreenPixelsPerInch')*res))];
93 | % Generate temporary file name
94 | tmp_nam = [tempname '.tif'];
95 | try
96 | % Ensure that the temp dir is writable (Javier Paredes 26/2/15)
97 | fid = fopen(tmp_nam,'w');
98 | fwrite(fid,1);
99 | fclose(fid);
100 | delete(tmp_nam); % cleanup
101 | isTempDirOk = true;
102 | catch
103 | % Temp dir is not writable, so use the current folder
104 | [dummy,fname,fext] = fileparts(tmp_nam); %#ok
105 | fpath = pwd;
106 | tmp_nam = fullfile(fpath,[fname fext]);
107 | isTempDirOk = false;
108 | end
109 | % Enable users to specify optional ghostscript options (issue #36)
110 | if nargin > 3 && ~isempty(gs_options)
111 | if iscell(gs_options)
112 | gs_options = sprintf(' %s',gs_options{:});
113 | elseif ~ischar(gs_options)
114 | error('gs_options input argument must be a string or cell-array of strings');
115 | else
116 | gs_options = [' ' gs_options];
117 | end
118 | else
119 | gs_options = '';
120 | end
121 | if nargin > 2 && strcmp(renderer, '-painters')
122 | % First try to print directly to image file
123 | try
124 | % Print the file into a temporary image file and read it into array A
125 | [A, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam);
126 | if err, rethrow(ex); end
127 | catch % error - try to print to EPS and then using Ghostscript to TIF
128 | % Ensure that ghostscript() exists on the Matlab path
129 | if ~exist('ghostscript','file') && isempty(which('ghostscript'))
130 | error('export_fig:print2array:ghostscript', 'The ghostscript.m function is required by print2array.m. Install the complete export_fig package from https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig or https://github.com/altmany/export_fig')
131 | end
132 | % Print to eps file
133 | if isTempDirOk
134 | tmp_eps = [tempname '.eps'];
135 | else
136 | tmp_eps = fullfile(fpath,[fname '.eps']);
137 | end
138 | print2eps(tmp_eps, fig, 0, renderer, '-loose');
139 | try
140 | % Initialize the command to export to tiff using ghostscript
141 | cmd_str = ['-dEPSCrop -q -dNOPAUSE -dBATCH ' res_str ' -sDEVICE=tiff24nc'];
142 | % Set the font path
143 | fp = font_path();
144 | if ~isempty(fp)
145 | cmd_str = [cmd_str ' -sFONTPATH="' fp '"'];
146 | end
147 | % Add the filenames
148 | cmd_str = [cmd_str ' -sOutputFile="' tmp_nam '" "' tmp_eps '"' gs_options];
149 | % Execute the ghostscript command
150 | ghostscript(cmd_str);
151 | catch me
152 | % Delete the intermediate file
153 | delete(tmp_eps);
154 | rethrow(me);
155 | end
156 | % Delete the intermediate file
157 | delete(tmp_eps);
158 | % Read in the generated bitmap
159 | A = imread(tmp_nam);
160 | % Delete the temporary bitmap file
161 | delete(tmp_nam);
162 | end
163 | else
164 | if nargin < 3
165 | renderer = '-opengl';
166 | end
167 | % Print the file into a temporary image file and read it into array A
168 | [A, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam);
169 | % Throw any error that occurred
170 | if err
171 | % Display suggested workarounds to internal print() error (issue #16)
172 | fprintf(2, 'An error occured with Matlab''s builtin print function.\nTry setting the figure Renderer to ''painters'' or use opengl(''software'').\n\n');
173 | rethrow(ex);
174 | end
175 | end
176 | end
177 |
178 | % Set the background color
179 | if isequal(bcol, 'none')
180 | bcol = squeeze(A(1,1,:));
181 | if ~all(bcol==0) %if not black
182 | bcol = [255,255,255]; %=white %=[];
183 | end
184 | else
185 | if all(bcol <= 1)
186 | bcol = bcol * 255;
187 | end
188 | if ~isequal(bcol, round(bcol))
189 | bcol = squeeze(A(1,1,:));
190 | %{
191 | % Set border pixels to the correct colour
192 | for l = 1:size(A, 2)
193 | if ~all(reshape(A(:,l,:) == 255, [], 1))
194 | break;
195 | end
196 | end
197 | for r = size(A, 2):-1:l
198 | if ~all(reshape(A(:,r,:) == 255, [], 1))
199 | break;
200 | end
201 | end
202 | for t = 1:size(A, 1)
203 | if ~all(reshape(A(t,:,:) == 255, [], 1))
204 | break;
205 | end
206 | end
207 | for b = size(A, 1):-1:t
208 | if ~all(reshape(A(b,:,:) == 255, [], 1))
209 | break;
210 | end
211 | end
212 | bcol = median(single([reshape(A(:,[l r],:), [], size(A, 3)); ...
213 | reshape(A([t b],:,:), [], size(A, 3))]), 1));
214 | for c = 1:size(A, 3)
215 | A(:,[1:l-1, r+1:end],c) = bcol(c);
216 | A([1:t-1, b+1:end],:,c) = bcol(c);
217 | end
218 | %}
219 | end
220 | end
221 | bcol = uint8(bcol);
222 |
223 | % Ensure that the output size is correct
224 | if isequal(res, round(res))
225 | px = round([px([4 3])*res 3]); % round() to avoid an indexing warning below
226 | if any(size(A) > px) %~isequal(size(A), px)
227 | A = A(1:min(end,px(1)),1:min(end,px(2)),:);
228 | end
229 | if any(size(alpha) > px(1:2))
230 | alpha = alpha(1:min(end,px(1)),1:min(end,px(2)));
231 | end
232 | end
233 | end
234 |
235 | % Get the Java-based screen-capture of the figure's JFrame content-panel
236 | function [imgData, alpha] = getJavaImage(hFig)
237 | % Get the figure's underlying Java frame
238 | oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame');
239 | warning('off','MATLAB:ui:javaframe:PropertyToBeRemoved');
240 | try
241 | jf = get(handle(hFig),'JavaFrame_I');
242 | catch
243 | jf = get(handle(hFig),'JavaFrame'); %#ok
244 | end
245 | warning(oldWarn);
246 |
247 | % Get the Java frame's root frame handle
248 | %jframe = jf.getFigurePanelContainer.getComponent(0).getRootPane.getParent;
249 | try
250 | jClient = jf.fHG2Client; % This works from R2014b and up
251 | catch
252 | try
253 | jClient = jf.fHG1Client; % This works from R2008b-R2014a
254 | catch
255 | jClient = jf.fFigureClient; % This works up to R2011a
256 | end
257 | end
258 |
259 | % Get the content-pane
260 | try
261 | jPanel = jClient.getContentPane;
262 | catch
263 | jPanel = jClient.getFigurePanelContainer;
264 | end
265 | jPanel.repaint;
266 | w = jPanel.getWidth;
267 | h = jPanel.getHeight;
268 |
269 | % Create a BufferedImage and paint the content-pane into it
270 | % (https://coderanch.com/t/470601/java/screenshot-JPanel)
271 | % Note: contrary to documentation and common-sense, it turns out that TYPE_INT_RGB
272 | % ^^^^ returns non-opaque alpha, while TYPE_INT_ARGB only returns 255s in the alpha channel
273 | jOriginalGraphics = jPanel.getGraphics;
274 | import java.awt.image.BufferedImage
275 | try TYPE_INT_RGB = BufferedImage.TYPE_INT_RGB; catch, TYPE_INT_RGB = 1; end
276 | jImage = BufferedImage(w, h, TYPE_INT_RGB);
277 | jPanel.paint(jImage.createGraphics);
278 | jPanel.paint(jOriginalGraphics); % repaint original figure to avoid a blank window
279 |
280 | % Extract the RGB pixels from the BufferedImage (see screencapture.m)
281 | pixelsData = reshape(typecast(jImage.getData.getDataStorage, 'uint8'), 4, w, h);
282 | imgData = cat(3, ...
283 | transpose(reshape(pixelsData(3, :, :), w, h)), ...
284 | transpose(reshape(pixelsData(2, :, :), w, h)), ...
285 | transpose(reshape(pixelsData(1, :, :), w, h)));
286 |
287 | % And now also the alpha channel (if available)
288 | alpha = transpose(reshape(pixelsData(4, :, :), w, h));
289 |
290 | % Ensure that the results are the expected size, otherwise raise an error
291 | figSize = getpixelposition(gcf);
292 | expectedSize = [figSize(4), figSize(3), 3];
293 | if ~isequal(expectedSize, size(imgData))
294 | error('bad Java screen-capture size!')
295 | end
296 | end
297 |
298 | % Export an image file of the figure using print() and then read it into an array
299 | function [imgData, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam)
300 | imgData = []; % fix for issue #254
301 | err = false;
302 | ex = [];
303 | alpha = [];
304 | % Temporarily set the paper size
305 | old_pos_mode = get(fig, 'PaperPositionMode');
306 | old_orientation = get(fig, 'PaperOrientation');
307 | set(fig, 'PaperPositionMode','auto', 'PaperOrientation','portrait');
308 | try
309 | % Workaround for issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() function)
310 | fp = []; % in case we get an error below
311 | fp = findall(fig, 'Type','patch', 'LineWidth',0.75);
312 | set(fp, 'LineWidth',0.5);
313 | try %if using_hg2(fig) % HG2 (R2014b or newer)
314 | % Use print('-RGBImage') directly (a bit faster than via temp image file)
315 | imgData = print(fig, renderer, res_str, '-RGBImage');
316 | catch %else % HG1 (R2014a or older)
317 | % Fix issue #83: use numeric handles in HG1
318 | fig = double(fig);
319 | % Print to image file
320 | print(fig, renderer, res_str, '-dtiff', tmp_nam);
321 | imgData = imread(tmp_nam);
322 | % Delete the temporary file
323 | delete(tmp_nam);
324 | end
325 | imgSize = size(imgData); imgSize = imgSize([1,2]); % Fix issue #308
326 | alpha = 255 * ones(imgSize, 'uint8'); % =all pixels opaque
327 | catch ex
328 | err = true;
329 | end
330 | set(fp, 'LineWidth',0.75); % restore original figure appearance
331 | % Reset the paper size
332 | set(fig, 'PaperPositionMode',old_pos_mode, 'PaperOrientation',old_orientation);
333 | end
334 |
335 | % Return (and create, where necessary) the font path (for use by ghostscript)
336 | function fp = font_path()
337 | fp = user_string('gs_font_path');
338 | if ~isempty(fp)
339 | return
340 | end
341 | % Create the path
342 | % Start with the default path
343 | fp = getenv('GS_FONTPATH');
344 | % Add on the typical directories for a given OS
345 | if ispc
346 | if ~isempty(fp)
347 | fp = [fp ';'];
348 | end
349 | fp = [fp getenv('WINDIR') filesep 'Fonts'];
350 | else
351 | if ~isempty(fp)
352 | fp = [fp ':'];
353 | end
354 | fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype'];
355 | end
356 | user_string('gs_font_path', fp);
357 | end
358 |
--------------------------------------------------------------------------------
/source_code/export_fig/read_write_entire_textfile.m:
--------------------------------------------------------------------------------
1 | %READ_WRITE_ENTIRE_TEXTFILE Read or write a whole text file to/from memory
2 | %
3 | % Read or write an entire text file to/from memory, without leaving the
4 | % file open if an error occurs.
5 | %
6 | % Reading:
7 | % fstrm = read_write_entire_textfile(fname)
8 | % Writing:
9 | % read_write_entire_textfile(fname, fstrm)
10 | %
11 | %IN:
12 | % fname - Pathname of text file to be read in.
13 | % fstrm - String to be written to the file, including carriage returns.
14 | %
15 | %OUT:
16 | % fstrm - String read from the file. If an fstrm input is given the
17 | % output is the same as that input.
18 |
19 | function fstrm = read_write_entire_textfile(fname, fstrm)
20 | modes = {'rt', 'wt'};
21 | writing = nargin > 1;
22 | fh = fopen(fname, modes{1+writing});
23 | if fh == -1
24 | error('Unable to open file %s.', fname);
25 | end
26 | try
27 | if writing
28 | fwrite(fh, fstrm, 'char*1');
29 | else
30 | fstrm = fread(fh, '*char')';
31 | end
32 | catch ex
33 | fclose(fh);
34 | rethrow(ex);
35 | end
36 | fclose(fh);
37 | end
38 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/ProjectData.type.Info.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/.gitignore.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/ImageSelection.class.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/ImageSelection.java.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/LICENSE.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/README.md.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/append_pdfs.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/copyfig.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/crop_borders.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/eps2pdf.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/export_fig.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/fix_lines.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/ghostscript.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/im2gif.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/isolate_axes.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/pdf2eps.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/pdftops.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/print2array.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/print2eps.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/user_string.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.Files/using_hg2.m.type.File.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/source_code/export_fig/user_string.m:
--------------------------------------------------------------------------------
1 | function [string, file_name] = user_string(string_name, string)
2 | %USER_STRING Get/set a user specific string
3 | %
4 | % Examples:
5 | % string = user_string(string_name)
6 | % isSaved = user_string(string_name, new_string)
7 | % [value, file_name] = user_string(...)
8 | %
9 | % Function to get and set a string in a system or user specific file. This
10 | % enables, for example, system specific paths to binaries to be saved.
11 | %
12 | % The specified string will be saved in a file named .txt,
13 | % either in a subfolder named .ignore under this file's folder, or in the
14 | % user's prefdir folder (in case this file's folder is non-writable).
15 | %
16 | % IN:
17 | % string_name - String containing the name of the string required, which
18 | % sets the filename storing the string: .txt
19 | % new_string - The new string to be saved in the .txt file
20 | %
21 | % OUT:
22 | % string - The currently saved string. Default: ''
23 | % isSaved - Boolean indicating whether the save was succesful
24 | % file_name - path of the .txt file used to contain the requested string
25 |
26 | % Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015-
27 |
28 | % This method of saving paths avoids changing .m files which might be in a
29 | % version control system. Instead it saves the user dependent paths in
30 | % separate files with a .txt extension, which need not be checked in to
31 | % the version control system. Thank you to Jonas Dorn for suggesting this
32 | % approach.
33 |
34 | % 10/01/2013 - Access files in text, not binary mode, as latter can cause
35 | % errors. Thanks to Christian for pointing this out.
36 | % 29/05/2015 - Save file in prefdir if current folder is non-writable (issue #74)
37 | % 09/01/2018 - Fix issue #232: if the string looks like a file/folder path, ensure it actually exists
38 | % 15/01/2020 - Added file_name output argument
39 |
40 | if ~ischar(string_name)
41 | error('string_name must be a string.');
42 | end
43 | % Create the full filename
44 | fname = [string_name '.txt'];
45 | dname = fullfile(fileparts(mfilename('fullpath')), '.ignore');
46 | file_name = fullfile(dname, fname);
47 | default_file_name = file_name;
48 | if nargin > 1
49 | % Set string
50 | if ~ischar(string)
51 | error('new_string must be a string.');
52 | end
53 | % Make sure the save directory exists
54 | %dname = fileparts(file_name);
55 | if ~exist(dname, 'dir')
56 | % Create the directory
57 | try
58 | if ~mkdir(dname)
59 | string = false;
60 | return
61 | end
62 | catch
63 | string = false;
64 | return
65 | end
66 | % Make it hidden
67 | try
68 | fileattrib(dname, '+h');
69 | catch
70 | end
71 | end
72 | % Write the file
73 | fid = fopen(file_name, 'wt');
74 | if fid == -1
75 | % file cannot be created/updated - use prefdir if file does not already exist
76 | % (if file exists but is simply not writable, don't create a duplicate in prefdir)
77 | if ~exist(file_name,'file')
78 | file_name = fullfile(prefdir, fname);
79 | fid = fopen(file_name, 'wt');
80 | end
81 | if fid == -1
82 | string = false;
83 | file_name = default_file_name;
84 | return
85 | end
86 | end
87 | try
88 | fprintf(fid, '%s', string);
89 | catch
90 | fclose(fid);
91 | string = false;
92 | return
93 | end
94 | fclose(fid);
95 | string = true;
96 | else
97 | % Get string
98 | fid = fopen(file_name, 'rt');
99 | if fid == -1
100 | % file cannot be read, try to read the file in prefdir
101 | file_name = fullfile(prefdir, fname);
102 | fid = fopen(file_name, 'rt');
103 | if fid == -1
104 | string = '';
105 | file_name = default_file_name;
106 | return
107 | end
108 | end
109 | string = fgetl(fid);
110 | fclose(fid);
111 |
112 | % Fix issue #232: if the string looks like a file/folder path, ensure it actually exists
113 | if ~isempty(string) && any(string=='\' | string=='/') && ~exist(string) %#ok
114 | string = '';
115 | end
116 | end
117 | end
118 |
--------------------------------------------------------------------------------
/source_code/export_fig/using_hg2.m:
--------------------------------------------------------------------------------
1 | %USING_HG2 Determine if the HG2 graphics engine is used
2 | %
3 | % tf = using_hg2(fig)
4 | %
5 | %IN:
6 | % fig - handle to the figure in question.
7 | %
8 | %OUT:
9 | % tf - boolean indicating whether the HG2 graphics engine is being used
10 | % (true) or not (false).
11 |
12 | % 19/06/2015 - Suppress warning in R2015b; cache result for improved performance
13 | % 06/06/2016 - Fixed issue #156 (bad return value in R2016b)
14 |
15 | function tf = using_hg2(fig)
16 | persistent tf_cached
17 | if isempty(tf_cached)
18 | try
19 | if nargin < 1, fig = figure('visible','off'); end
20 | oldWarn = warning('off','MATLAB:graphicsversion:GraphicsVersionRemoval');
21 | try
22 | % This generates a [supressed] warning in R2015b:
23 | tf = ~graphicsversion(fig, 'handlegraphics');
24 | catch
25 | tf = ~verLessThan('matlab','8.4'); % =R2014b
26 | end
27 | warning(oldWarn);
28 | catch
29 | tf = false;
30 | end
31 | if nargin < 1, delete(fig); end
32 | tf_cached = tf;
33 | else
34 | tf = tf_cached;
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/source_code/plot_functions/create_plots.m:
--------------------------------------------------------------------------------
1 | function cycle_data = create_plots(x,fixed_parameters,filename_suffix)
2 |
3 | % Load setting for beautiful plots
4 | set_plot_options()
5 |
6 | % Evaluate the optimization problem
7 | fixed_parameters.calc_detail = 'long';
8 | if nargin == 2
9 | filename = fixed_parameters.project_name;
10 | elseif nargin == 3
11 | filename = [fixed_parameters.project_name, '_', filename_suffix];
12 | else
13 | error('The number of arguments must be 2 or 3')
14 | end
15 | filepath = fixed_parameters.results_path;
16 | cycle_data = evaluate_optimization_problem(x,fixed_parameters);
17 |
18 | % Choose whether to save the plots or not
19 | % 'choose_plots' is an structure that contains what diagrams to draw
20 | save = fixed_parameters.choose_plots.save;
21 |
22 | % Plot temperature vs heat flow rate diagram
23 | if strcmp(fixed_parameters.choose_plots.diagram_TQ,'yes')
24 | plot_TQ_diagram(cycle_data,filename,filepath,save)
25 | end
26 |
27 | % Plot temperature vs entropy diagram
28 | if strcmp(fixed_parameters.choose_plots.diagram_Ts,'yes')
29 | plot_Ts_diagram(cycle_data,filename,filepath,save)
30 | end
31 |
32 | % Plot temperature vs enthalpy diagram
33 | if strcmp(fixed_parameters.choose_plots.diagram_Th,'yes')
34 | plot_Th_diagram(cycle_data,filename,filepath,save)
35 | end
36 |
37 | end
38 |
--------------------------------------------------------------------------------
/source_code/plot_functions/plot_TQ_diagram.m:
--------------------------------------------------------------------------------
1 | function [] = plot_TQ_diagram(cycle_data,my_filename,my_path,save)
2 | %% Load the trajectories in the components
3 | % Evaporator
4 | h_evap_h = cycle_data.evaporator.h_h/1000;
5 | T_evap_h = cycle_data.evaporator.T_h-273.15;
6 | T_evap_c = cycle_data.evaporator.T_c-273.15;
7 |
8 | % Condenser
9 | h_cond_h = cycle_data.condenser.h_h/1000;
10 | T_cond_h = cycle_data.condenser.T_h-273.15;
11 | T_cond_c = cycle_data.condenser.T_c-273.15;
12 |
13 | % Recuperator
14 | h_rec_h = cycle_data.recuperator.h_h/1000;
15 | T_rec_h = cycle_data.recuperator.T_h-273.15;
16 | T_rec_c = cycle_data.recuperator.T_c-273.15;
17 |
18 | % Compute the heat flow rates
19 | m_h = cycle_data.mass_flows.m_h;
20 | m_f = cycle_data.mass_flows.m_f;
21 | q_evap = (h_evap_h-h_evap_h(1))*m_h;
22 | q_cond = (h_cond_h-h_cond_h(1))*m_f;
23 | q_rec = (h_rec_h-h_rec_h(1))*m_f;
24 |
25 |
26 | %% Plot the T-Q diagram
27 | % Prepare the figure
28 | fig = figure(); ax_fig = gca;
29 | hold on; box on; axis square;
30 |
31 | % Label de axes
32 | font_size = 12;
33 | xlabel({' '; '$\dot{Q}$ -- Heat transfer (kW)'},'FontSize',font_size)
34 | ylabel({'$T$ -- Temperature ($^\circ$C)';' '},'FontSize',font_size)
35 | ax_fig.XAxis.TickLabelFormat = '%.0f';
36 | ax_fig.YAxis.TickLabelFormat = '%.0f';
37 |
38 | plot(0,0,'r')
39 | plot(0,0,'k')
40 | plot(0,0,'b')
41 |
42 | plot(q_cond,T_cond_c,'b')
43 | plot(q_cond,T_cond_h,'k')
44 | plot((q_cond(end)+q_rec),T_rec_h,'k')
45 | plot((q_cond(end)+q_rec),T_rec_c,'k')
46 | plot((q_cond(end)+q_rec(end)+q_evap),T_evap_h,'r')
47 | plot((q_cond(end)+q_rec(end)+q_evap),T_evap_c,'k')
48 |
49 | x_lim = ax_fig.XLim;
50 | y_lim = ax_fig.YLim;
51 |
52 | plot([q_cond(end) q_cond(end)],[-10000 10000],'k','LineWidth',0.50)
53 | plot([q_cond(end)+q_rec(end) q_cond(end)+q_rec(end)],[-10000 10000],'k','LineWidth',0.50)
54 | plot([q_cond(end)+q_rec(end)+q_evap(end) q_cond(end)+q_rec(end)+q_evap(end)],[-10000 10000],'k','LineWidth',0.50)
55 |
56 | ax_fig.XLim = x_lim;
57 | ax_fig.YLim = y_lim;
58 |
59 | % Save the figure
60 | name = 'TQ_diagram';
61 | if save == 1
62 | saveas(fig,fullfile(my_path,[my_filename,'_',name,'.pdf']),'pdf')
63 | elseif save == 2
64 | % saveas(fig,fullfile(my_path,[my_filename,'_',name]),'fig')
65 | % export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-png','-r1000')
66 | % export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-eps','-painters')
67 | export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-pdf','-painters')
68 | elseif save ~= 0
69 | error('Choose a valid saving option')
70 | end
71 |
72 | end
73 |
--------------------------------------------------------------------------------
/source_code/plot_functions/plot_Th_diagram.m:
--------------------------------------------------------------------------------
1 | function [] = plot_Th_diagram(cycle_data,my_filename,my_path,save)
2 | %% Load the cycle points
3 | h_cycle = [cycle_data.cycle_states.h]/1000;
4 | T_cycle = [cycle_data.cycle_states.T]-273.15;
5 | working_fluid = cycle_data.fluids.working_fluid;
6 | T_min = cycle_data.properties.T_min-273.15;
7 | T_trip = cycle_data.properties.T_trip-273.15;
8 | T_crit = cycle_data.properties.T_crit-273.15;
9 |
10 |
11 | %% Load the trajectories in the components
12 | % Evaporator
13 | h_evap_c = cycle_data.evaporator.h_c/1000;
14 | T_evap_c = cycle_data.evaporator.T_c-273.15;
15 | T_evap_h = cycle_data.evaporator.T_h-273.15;
16 |
17 | % Condenser
18 | h_cond_h = cycle_data.condenser.h_h/1000;
19 | T_cond_h = cycle_data.condenser.T_h-273.15;
20 | T_cond_c = cycle_data.condenser.T_c-273.15;
21 |
22 | % Recuperator
23 | h_rec_c = cycle_data.recuperator.h_c/1000;
24 | h_rec_h = cycle_data.recuperator.h_h/1000;
25 | T_rec_c = cycle_data.recuperator.T_c-273.15;
26 | T_rec_h = cycle_data.recuperator.T_h-273.15;
27 |
28 | % Expander
29 | h_exp = cycle_data.expander.h/1000;
30 | T_exp = cycle_data.expander.T-273.15;
31 |
32 | % Pump
33 | h_pump = cycle_data.pump_f.h/1000;
34 | T_pump = cycle_data.pump_f.T-273.15;
35 |
36 |
37 | %% Plot the T-h diagram
38 | % Prepare the figure
39 | fig = figure(); ax_fig = gca;
40 | hold on; box on;
41 | pbaspect([1 1 1])
42 | % axis square;
43 |
44 | % Define the axis limits
45 | TT = T_cycle(1:end);
46 | hh = h_cycle(4:9);
47 | T_minplot = min(0.90*T_min,min(TT)-(max(TT)-min(TT))/8);
48 | T_maxplot = max(1.10*T_crit,max(TT)+(max(TT)-min(TT))/8);
49 | if T_min < T_crit
50 | [~, h_sat] = sat_line(working_fluid,T_min+273.15,T_crit+273.15,'T','H',200); h_sat = h_sat/1000;
51 | h_minplot = min(h_sat(1)-(h_sat(end)-h_sat(1))/8,min(hh)-(max(hh)-min(hh))/8);
52 | h_maxplot = max(1.2*max(h_sat),max(hh)+(max(hh)-min(hh))/8);
53 | else
54 | h_minplot = min(hh)-(max(hh)-min(hh))/8;
55 | h_maxplot = max(hh)+(max(hh)-min(hh))/8;
56 | end
57 |
58 | axis([h_minplot h_maxplot T_minplot T_maxplot])
59 |
60 | % Label de axes
61 | font_size = 12;
62 | xlabel({' ';'$h$ -- Enthalpy (kJ/kg)'},'FontSize',font_size);
63 | ylabel({'$T$ -- Temperature ($^\circ$C)';' '},'FontSize',font_size);
64 | ax_fig.YAxis.TickLabelFormat = '%.0f';
65 | ax_fig.XAxis.TickLabelFormat = '%.0f';
66 |
67 | % Plot theaturation line
68 | [T_sat, h_sat] = sat_line(working_fluid,T_trip+273.15,T_crit+273.15,'T','H',200);
69 | T_sat = T_sat-273.15; h_sat = h_sat/1000;
70 | plot(h_sat,T_sat,'k','LineWidth',0.5)
71 |
72 | % Plot the thermodynamic trajectories in the components
73 | plot(h_pump,T_pump,'k')
74 | plot(h_exp,T_exp,'k')
75 | plot(h_rec_h,T_rec_h,'k')
76 | plot(h_rec_c,T_rec_c,'k')
77 | plot(h_evap_c,T_evap_c,'k')
78 | plot(h_cond_h,T_cond_h,'k')
79 | plot(h_evap_c,T_evap_h,'r')
80 | plot(h_cond_h,T_cond_c,'b')
81 |
82 | % Plot the cycle points
83 | plot(h_cycle(4:9),T_cycle(4:9),'ko','MarkerFaceColor','k','MarkerSize',2)
84 | plot(h_cycle([7,6,6]),T_cycle([1,2,3]),'ro','MarkerFaceColor','r','MarkerSize',2)
85 | plot(h_cycle([4,4,9]),T_cycle([10,11,12]),'bo','MarkerFaceColor','b','MarkerSize',2)
86 | plot(h_cycle([6,6]),T_cycle([2,3]),'r-')
87 | plot(h_cycle([4,4]),T_cycle([10,11]),'b-')
88 |
89 | % Label the cycle points
90 | p1 = '$\quad 1$'; text(h_cycle(7),T_cycle(1), p1, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
91 | p2 = '$2 \quad$'; text(h_cycle(6),T_cycle(2)-3, p2, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
92 | p3 = '$3 \quad$'; text(h_cycle(6),T_cycle(3)+3, p3, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
93 | p4 = '$4 \quad$'; text(h_cycle(4),T_cycle(4)-3, p4, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
94 | p5 = '$5 \quad$'; text(h_cycle(5),T_cycle(5)+3, p5, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
95 | p6 = '$6 \quad$'; text(h_cycle(6),T_cycle(6)+6, p6, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
96 | p7 = '$\quad 7$'; text(h_cycle(7),T_cycle(7), p7, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
97 | p8 = '$\quad 8$'; text(h_cycle(8),T_cycle(8)+3, p8, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
98 | p9 = '$\quad 9$'; text(h_cycle(9),T_cycle(9)-3, p9, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
99 | p10 = '$10 \quad$'; text(h_cycle(4),T_cycle(10)-3, p10, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
100 | p11 = '$11 \quad$'; text(h_cycle(4),T_cycle(11)+3, p11, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
101 | p12 = '$\quad 12$'; text(h_cycle(9),T_cycle(12), p12, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
102 |
103 | % Save the figure
104 | name = 'Th_diagram';
105 | if save == 1
106 | saveas(fig,fullfile(my_path,[my_filename,'_',name,'.pdf']),'pdf')
107 | elseif save == 2
108 | % saveas(fig,fullfile(my_path,[my_filename,'_',name]),'fig')
109 | % export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-png','-r1000')
110 | % export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-eps','-painters')
111 | export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-pdf','-painters')
112 | elseif save ~= 0
113 | error('Choose a valid saving option')
114 | end
115 |
116 | end
117 |
--------------------------------------------------------------------------------
/source_code/plot_functions/plot_Ts_diagram.m:
--------------------------------------------------------------------------------
1 | function [] = plot_Ts_diagram(cycle_data,my_filename,my_path,save)
2 | %% Load the cycle points
3 | s_cycle = [cycle_data.cycle_states.s]/1000;
4 | T_cycle = [cycle_data.cycle_states.T]-273.15;
5 | working_fluid = cycle_data.fluids.working_fluid;
6 | T_min = cycle_data.properties.T_min-273.15;
7 | T_trip = cycle_data.properties.T_trip-273.15;
8 | T_crit = cycle_data.properties.T_crit-273.15;
9 |
10 |
11 | %% Load the trajectories in the components
12 | % Evaporator
13 | s_evap_c = cycle_data.evaporator.s_c/1000;
14 | T_evap_c = cycle_data.evaporator.T_c-273.15;
15 | T_evap_h = cycle_data.evaporator.T_h-273.15;
16 |
17 | % Condenser
18 | s_cond_h = cycle_data.condenser.s_h/1000;
19 | T_cond_h = cycle_data.condenser.T_h-273.15;
20 | T_cond_c = cycle_data.condenser.T_c-273.15;
21 |
22 | % Recuperator
23 | s_rec_c = cycle_data.recuperator.s_c/1000;
24 | s_rec_h = cycle_data.recuperator.s_h/1000;
25 | T_rec_c = cycle_data.recuperator.T_c-273.15;
26 | T_rec_h = cycle_data.recuperator.T_h-273.15;
27 |
28 | % Expander
29 | s_exp = cycle_data.expander.s/1000;
30 | T_exp = cycle_data.expander.T-273.15;
31 |
32 | % Pump
33 | s_pump = cycle_data.pump_f.s/1000;
34 | T_pump = cycle_data.pump_f.T-273.15;
35 |
36 |
37 | %% Plot the T-s diagram
38 | % Prepare the figure
39 | fig = figure(); ax_fig = gca;
40 | hold on; box on;
41 | pbaspect([1 1 1])
42 | % axis square;
43 |
44 | % Define the axis limits
45 | TT = T_cycle(1:end);
46 | ss = s_cycle(4:9);
47 | T_minplot = min(0.90*T_min,min(TT)-(max(TT)-min(TT))/8);
48 | T_maxplot = max(1.10*T_crit,max(TT)+(max(TT)-min(TT))/8);
49 | if T_min < T_crit
50 | [~, s_sat] = sat_line(working_fluid,T_min+273.15,T_crit+273.15,'T','S',200); s_sat = s_sat/1000;
51 | s_minplot = min(s_sat(1)-(s_sat(end)-s_sat(1))/8,min(ss)-(max(ss)-min(ss))/8);
52 | s_maxplot = max(1.2*max(s_sat),max(ss)+(max(ss)-min(ss))/8);
53 | else
54 | s_minplot = min(ss)-(max(ss)-min(ss))/8;
55 | s_maxplot = max(ss)+(max(ss)-min(ss))/8;
56 | end
57 | axis([s_minplot s_maxplot T_minplot T_maxplot])
58 |
59 | % Label de axes
60 | font_size = 12;
61 | xlabel({' ';'$s$ -- Entropy (kJ/kg$\,$K)'},'FontSize',font_size);
62 | ylabel({'$T$ -- Temperature ($^\circ$C)';' '},'FontSize',font_size);
63 | ax_fig.YAxis.TickLabelFormat = '%.0f';
64 | ax_fig.XAxis.TickLabelFormat = '%.2f';
65 |
66 | % Plot theaturation line
67 | [T_sat, s_sat] = sat_line(working_fluid,T_trip+273.15,T_crit+273.15,'T','S',200);
68 | T_sat = T_sat-273.15; s_sat = s_sat/1000;
69 | plot(s_sat,T_sat,'k','LineWidth',0.5)
70 |
71 | % Plot the thermodynamic trajectories in the components
72 | plot(s_pump,T_pump,'k')
73 | plot(s_exp,T_exp,'k')
74 | plot(s_rec_h,T_rec_h,'k')
75 | plot(s_rec_c,T_rec_c,'k')
76 | plot(s_cond_h,T_cond_h,'k')
77 | plot(s_evap_c,T_evap_c,'k')
78 | plot(s_cond_h,T_cond_h,'k')
79 | plot(s_evap_c,T_evap_h,'r')
80 | plot(s_cond_h,T_cond_c,'b')
81 |
82 | % Plot the cycle points
83 | plot(s_cycle(4:9),T_cycle(4:9),'ko','MarkerFaceColor','k','MarkerSize',2)
84 | plot(s_cycle([7,6,6]),T_cycle([1,2,3]),'ro','MarkerFaceColor','r','MarkerSize',2)
85 | plot(s_cycle([4,4,9]),T_cycle([10,11,12]),'bo','MarkerFaceColor','b','MarkerSize',2)
86 | plot(s_cycle([6,6]),T_cycle([2,3]),'r-')
87 | plot(s_cycle([4,4]),T_cycle([10,11]),'b-')
88 |
89 | % Label the cycle points
90 | p1 = '$\quad 1$'; text(s_cycle(7),T_cycle(1), p1, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
91 | p2 = '$2 \quad$'; text(s_cycle(6),T_cycle(2)-3, p2, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
92 | p3 = '$3 \quad$'; text(s_cycle(6),T_cycle(3)+3, p3, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
93 | p4 = '$4 \quad$'; text(s_cycle(4),T_cycle(4)-3, p4, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
94 | p5 = '$5 \quad$'; text(s_cycle(5),T_cycle(5)+3, p5, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
95 | p6 = '$6 \quad$'; text(s_cycle(6),T_cycle(6)+6, p6, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
96 | p7 = '$\quad 7$'; text(s_cycle(7),T_cycle(7), p7, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
97 | p8 = '$\quad 8$'; text(s_cycle(8),T_cycle(8)+3, p8, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
98 | p9 = '$\quad 9$'; text(s_cycle(9),T_cycle(9)-3, p9, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
99 | p10 = '$10 \quad$'; text(s_cycle(4),T_cycle(10)-3, p10, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
100 | p11 = '$11 \quad$'; text(s_cycle(4),T_cycle(11)+3, p11, 'HorizontalAlignment', 'right', 'FontSize', font_size-2)
101 | p12 = '$\quad 12$'; text(s_cycle(9),T_cycle(12), p12, 'HorizontalAlignment', 'left', 'FontSize', font_size-2)
102 |
103 | % Save the figure
104 | name = 'Ts_diagram';
105 | if save == 1
106 | saveas(fig,fullfile(my_path,[my_filename,'_',name,'.pdf']),'pdf')
107 | elseif save == 2
108 | % saveas(fig,fullfile(my_path,[my_filename,'_',name]),'fig')
109 | % export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-png','-r1000')
110 | % export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-eps','-painters')
111 | export_fig(fig,fullfile(my_path,[my_filename,'_',name]),'-pdf','-painters')
112 | elseif save ~= 0
113 | error('Choose a valid saving option')
114 | end
115 |
116 | end
117 |
--------------------------------------------------------------------------------
/source_code/plot_functions/set_plot_options.m:
--------------------------------------------------------------------------------
1 | function set_plot_options
2 | %% Printing options
3 | FontName = 'monospace';
4 | FontSize = 11;
5 | AxLineWidth = 0.75;
6 | LineWidth = 1.00;
7 | MarkerSize = 5;
8 |
9 | % Setting LaTeX as text interpreter
10 | set(groot,'DefaultTextInterpreter','latex', ...
11 | 'DefaultAxesTickLabelInterpreter','latex', ...
12 | 'DefaultLegendInterpreter','latex');
13 |
14 | % Setting several default options for the graphics
15 | set(groot, 'DefaultFigureColor','White' , ...
16 | 'DefaultFigurePaperType', 'a4letter', ...
17 | 'DefaultAxesColor', 'white', ...
18 | 'DefaultAxesFontUnits', 'points',...
19 | 'DefaultAxesFontSize', FontSize, ...
20 | 'DefaultAxesFontAngle', 'normal', ...
21 | 'DefaultAxesGridLineStyle', '-', ...
22 | 'DefaultAxesGridAlpha', 0.25, ...
23 | 'DefaultAxesGridColor', [0, 0, 0], ...
24 | 'DefaultAxesInterruptible', 'on', ...
25 | 'DefaultAxesLayer', 'Bottom', ...
26 | 'DefaultAxesNextPlot', 'replace', ...
27 | 'DefaultAxesUnits', 'normalized', ...
28 | 'DefaultAxesXcolor', [0, 0, 0], ...
29 | 'DefaultAxesYcolor', [0, 0, 0], ...
30 | 'DefaultAxesZcolor', [0, 0, 0], ...
31 | 'DefaultAxesVisible', 'on', ...
32 | 'DefaultAxesLineWidth', AxLineWidth, ...
33 | 'DefaultLineLineWidth', LineWidth, ...
34 | 'DefaultLineMarkerSize', MarkerSize, ...
35 | 'DefaultTextColor', [0, 0, 0], ...
36 | 'DefaultTextFontUnits', 'Points', ...
37 | 'DefaultTextFontName', FontName, ... % Not applied when LaTeX is used
38 | 'DefaultAxesFontName', FontName, ... % Not applied when LaTeX is used
39 | 'DefaultTextFontSize', FontSize, ...
40 | 'DefaultTextVerticalAlignment', 'middle', ...
41 | 'DefaultTextHorizontalAlignment', 'left')
42 |
43 | % Setting a position for the figure
44 | set(groot,'DefaultFigurePosition', [360 198 560 420]);
45 |
46 | end
47 |
--------------------------------------------------------------------------------
/source_code/print_solution.m:
--------------------------------------------------------------------------------
1 | function [] = print_solution(cycle_data)
2 |
3 | % Print bounds
4 | bounds_summary = cycle_data.optimization.bounds_summary;
5 | header = bounds_summary.header;
6 | name = bounds_summary.name;
7 | value = bounds_summary.value;
8 | value_min = bounds_summary.value_min;
9 | value_max = bounds_summary.value_max;
10 | satisfied = bounds_summary.satisfied;
11 | active = bounds_summary.active;
12 | fprintf('\n')
13 | fprintf('|---------------------------------------------------------------------------------------------------------------|\n')
14 | fprintf('|---------------------------------- Values and bounds of the design variables ----------------------------------|\n')
15 | fprintf('|---------------------------------------------------------------------------------------------------------------|\n')
16 | fprintf('%31s %15s %12s %15s %12s %10s \n', header{1}, header{2}, header{3}, header{4}, header{5}, header{6});
17 | for i = 1:size(name,2)
18 | fprintf('%31s %15.4f %12.4f %15.4f %12s %10s \n', name{i}, value_min{i}, value{i}, value_max{i}, satisfied{i}, active{i});
19 | end
20 | fprintf('|---------------------------------------------------------------------------------------------------------------|\n')
21 |
22 | % Print constraints
23 | constraint_summary = cycle_data.optimization.constraint_summary;
24 | header = constraint_summary.header;
25 | name = constraint_summary.name;
26 | value = constraint_summary.value;
27 | value_min = constraint_summary.value_min;
28 | value_max = constraint_summary.value_max;
29 | applied = constraint_summary.applied;
30 | satisfied = constraint_summary.satisfied;
31 | active = constraint_summary.active;
32 | fprintf('\n')
33 | fprintf('|---------------------------------------------------------------------------------------------------------------|\n')
34 | fprintf('|--------------------------------- Values and limits of the problem constraints --------------------------------|\n')
35 | fprintf('|---------------------------------------------------------------------------------------------------------------|\n')
36 | fprintf('%31s %15s %12s %15s %10s %12s %10s \n', header{1}, header{2}, header{3}, header{4}, header{5}, header{6}, header{7});
37 | for i = 1:size(name,2)
38 | fprintf('%31s %15.4f %12.4f %15.4f %10s %12s %10s \n', name{i}, value_min{i}, value{i}, value_max{i}, applied{i}, satisfied{i}, active{i});
39 | end
40 | fprintf('|---------------------------------------------------------------------------------------------------------------|\n')
41 |
42 | end
--------------------------------------------------------------------------------
/source_code/property_functions/cluster_func.m:
--------------------------------------------------------------------------------
1 | function f = cluster_func(z,beta)
2 | % Muller introduced this function in his notes (I should find a reference)
3 | % 01 is the clustering parameter
5 |
6 | f = 1 + beta*(1-((beta+1)/(beta-1)).^(1-z))./(1+((beta+1)/(beta-1)).^(1-z));
7 |
8 | % The cluster function puts more points in the region where z is close to 0
9 | % If you want more points in the region where z is close to 1 define the
10 | % problem in the opposite manner and then reverse the resulting vector
11 |
12 | end
--------------------------------------------------------------------------------
/source_code/property_functions/liq_line.m:
--------------------------------------------------------------------------------
1 | function [X_liq, Y_liq] = liq_line(fluid,T_min,T_max,x,y,N_liq)
2 |
3 | % Clustering parameter (>1)
4 | beta = 1.0010;
5 |
6 | % Liquid saturation line
7 | z_liq = linspace(0,1,N_liq)';
8 | T_liq = T_max+cluster_func(z_liq,beta)*(T_min-T_max);
9 | T_liq(1:end) = T_liq(end:-1:1); % Reverse the vector (clustering)
10 | X_liq = zeros(N_liq,1); % Pre-allocate space
11 | Y_liq = zeros(N_liq,1); % Pre-allocate space
12 | for i = 1:N_liq
13 | X_liq(i) = prop_calculation(x,'T',T_liq(i),'Q',0,fluid);
14 | Y_liq(i) = prop_calculation(y,'T',T_liq(i),'Q',0,fluid);
15 | end
16 |
17 | end
--------------------------------------------------------------------------------
/source_code/property_functions/prop_calculation.m:
--------------------------------------------------------------------------------
1 | function prop = prop_calculation(varargin)
2 |
3 | % CoolProp function call
4 | prop = py.CoolProp.CoolProp.PropsSI(varargin{:});
5 |
6 | % REFPROP function call
7 | % prop = refpropm(varargin{:});
8 |
9 | end
--------------------------------------------------------------------------------
/source_code/property_functions/quality.m:
--------------------------------------------------------------------------------
1 | function q = quality(prop2,prop2_value,fluid,p,p_crit)
2 |
3 | % Give an output for quality even if the pressure is supercritical
4 | if p < p_crit
5 | q = prop_calculation('Q','P',p,prop2,prop2_value,fluid);
6 | elseif p>= p_crit
7 | q = 1.1;
8 | else
9 | error('Ooops, something went wrong in quality computation');
10 | end
11 |
12 | if q < 0
13 | q = 1.1;
14 |
15 | end
--------------------------------------------------------------------------------
/source_code/property_functions/sat_line.m:
--------------------------------------------------------------------------------
1 | function [X_sat, Y_sat] = sat_line(fluid,T_min,T_max,x,y,N)
2 |
3 | % Compute the liquid and the vapor saturation lines
4 | [X_liq, Y_liq] = liq_line(fluid,T_min,T_max,x,y,ceil(N/2));
5 | [X_vap, Y_vap] = vap_line(fluid,T_min,T_max,x,y,floor(N/2));
6 |
7 | % Export the results
8 | X_sat = [X_liq; X_vap]; % Create a single vector with property x
9 | Y_sat = [Y_liq; Y_vap]; % Create a single vector with property y
10 |
11 | end
--------------------------------------------------------------------------------
/source_code/property_functions/vap_line.m:
--------------------------------------------------------------------------------
1 | function [X_vap, Y_vap] = vap_line(fluid,T_min,T_max,x,y,N_vap)
2 |
3 | % Clustering parameter (>1)
4 | beta = 1.0010;
5 |
6 | % Vapor saturation line
7 | z_vap = linspace(0,1,N_vap)';
8 | T_vap = T_max+cluster_func(z_vap,beta)*(T_min-T_max);
9 | X_vap = zeros(N_vap,1); % Pre-allocate space
10 | Y_vap = zeros(N_vap,1); % Pre-allocate space
11 | for i = 1:N_vap
12 | X_vap(i) = prop_calculation(x,'T',T_vap(i),'Q',1,fluid);
13 | Y_vap(i) = prop_calculation(y,'T',T_vap(i),'Q',1,fluid);
14 | end
15 |
16 | end
--------------------------------------------------------------------------------
/source_code/save_current_solution.m:
--------------------------------------------------------------------------------
1 | function stop = save_current_solution(x,~,~,fixed_parameters)
2 |
3 | % Use a persistent variable to keep track of the number of iterations
4 | persistent iter
5 | if isempty(iter)
6 | iter = 0;
7 | end
8 | iter = iter+1;
9 |
10 | % Evaluate the cycle model for the current vector of independent variables
11 | fixed_parameters.calc_detail = 'short';
12 | cycle_data = evaluate_rankine_cycle(x,fixed_parameters);
13 |
14 | % Save the current solution as a MATLAB data structure
15 | save(fullfile(fixed_parameters.results_path,[fixed_parameters.project_name, '_', num2str(iter,'%02d'), '.mat']),'cycle_data')
16 |
17 | % Return a false stop flag
18 | stop = false;
19 |
20 | end
--------------------------------------------------------------------------------
/source_code/save_solution.m:
--------------------------------------------------------------------------------
1 | function [] = save_solution(cycle_data,my_filename,my_path)
2 |
3 | % Print optimization problem output
4 | file_name = fopen(fullfile(my_path,[my_filename,'_solution_optimization.txt']), 'w');
5 | bounds_summary = cycle_data.optimization.bounds_summary;
6 | header = bounds_summary.header;
7 | name = bounds_summary.name;
8 | value = bounds_summary.value;
9 | value_min = bounds_summary.value_min;
10 | value_max = bounds_summary.value_max;
11 | satisfied = bounds_summary.satisfied;
12 | active = bounds_summary.active;
13 | fprintf(file_name,'|---------------------------------------------------------------------------------------------------------------|\n');
14 | fprintf(file_name,'|---------------------------------- Values and bounds of the design variables ----------------------------------|\n');
15 | fprintf(file_name,'|---------------------------------------------------------------------------------------------------------------|\n');
16 | fprintf(file_name,'%31s %15s %12s %15s %12s %10s \n', header{1}, header{2}, header{3}, header{4}, header{5}, header{6});
17 | for i = 1:size(name,2)
18 | fprintf(file_name,'%31s %15.4f %12.4f %15.4f %12s %10s \n', name{i}, value_min{i}, value{i}, value_max{i}, satisfied{i}, active{i});
19 | end
20 | fprintf(file_name,'|---------------------------------------------------------------------------------------------------------------|\n');
21 |
22 | constraint_summary = cycle_data.optimization.constraint_summary;
23 | header = constraint_summary.header;
24 | name = constraint_summary.name;
25 | value = constraint_summary.value;
26 | value_min = constraint_summary.value_min;
27 | value_max = constraint_summary.value_max;
28 | applied = constraint_summary.applied;
29 | satisfied = constraint_summary.satisfied;
30 | active = constraint_summary.active;
31 | fprintf(file_name,'\n');
32 | fprintf(file_name,'|---------------------------------------------------------------------------------------------------------------|\n');
33 | fprintf(file_name,'|--------------------------------- Values and limits of the problem constraints --------------------------------|\n');
34 | fprintf(file_name,'|---------------------------------------------------------------------------------------------------------------|\n');
35 | fprintf(file_name,'%31s %15s %12s %15s %10s %12s %10s \n', header{1}, header{2}, header{3}, header{4}, header{5}, header{6}, header{7});
36 | for i = 1:size(name,2)
37 | fprintf(file_name,'%31s %15.4f %12.4f %15.4f %10s %12s %10s \n', name{i}, value_min{i}, value{i}, value_max{i}, applied{i}, satisfied{i}, active{i});
38 | end
39 | fprintf(file_name,'|---------------------------------------------------------------------------------------------------------------|\n');
40 | fclose(file_name);
41 |
42 | end
--------------------------------------------------------------------------------
/source_code/solve_optimization_problem.m:
--------------------------------------------------------------------------------
1 | function [cycle_data,x_opt,f_opt,exitflag,output,lambda] = solve_optimization_problem(fixed_parameters,optimization_problem)
2 |
3 | % This function is used to have a temporal storage of the objective
4 | % function and the constraints and avoid the evaluation of the model
5 | % each time the objective function or the constraints are required
6 | % (this function might look complex, but it is just a trick to speed the
7 | % optimization speed by a factor of 2)
8 |
9 | x_last = []; % Degrees of freedom in the last computation
10 | f_bis = []; % Objective function in storage
11 | c_bis = []; % Nonlinear inequality constraints in storage
12 | c_eq_bis = []; % Nonlinear equality constraints in storage
13 |
14 | % Objective function and nonlinear constraints functions (nested below)
15 | fixed_parameters.calc_detail = 'short';
16 | optimization_problem.objective = @(x) evaluate_objective_function(x,fixed_parameters);
17 | optimization_problem.nonlcon = @(x) evaluate_constraints(x,fixed_parameters);
18 |
19 | % Use fmincon to solve the optimization problem
20 | tic
21 | [x_opt,f_opt,exitflag,output,lambda] = fmincon(optimization_problem);
22 | cycle_data = evaluate_optimization_problem(x_opt,fixed_parameters);
23 | t = toc;
24 | disp(['The optimization problem was solved in ', num2str(t), ' seconds'])
25 | disp(['The optimization exit flag is ', num2str(exitflag)])
26 |
27 |
28 | function f = evaluate_objective_function(x,fixed_parameters)
29 | if ~isequal(x,x_last) % Check if computation is necessary
30 | [~,f_bis,c_bis,c_eq_bis] = evaluate_optimization_problem(x,fixed_parameters);
31 | x_last = x;
32 | end
33 | f = f_bis;
34 | end
35 |
36 | function [c, c_eq] = evaluate_constraints(x,fixed_parameters)
37 | if ~isequal(x,x_last) % Check if computation is necessary
38 | [~,f_bis,c_bis,c_eq_bis] = evaluate_optimization_problem(x,fixed_parameters);
39 | x_last = x;
40 | end
41 | c = c_bis;
42 | c_eq = c_eq_bis;
43 | end
44 |
45 |
46 | end
47 |
48 |
--------------------------------------------------------------------------------