%% Example of a surface-mounted permanent magnet synchronous motor optimization script 
% See section 6.3 of User Manual - Part II for more details.
% This script implements the automatic optimization of a surface-mounted permanent magnet synchronous motor
% minimizing two objectives (motor weight and motor losses for the target operating point of 1.8 kW and 3000 RPM)
% by varying several geometry parameters of the motor. The base design mxp-file for this example can be found in
% SimFiles\OptimizationBaseDesign\BaseDesign12s14pOutrunner.mxp. The parallel processing is used to speed up 
% the optimization process allowing running FE simulations for several designs at the same time. 
% See also file \CustomScripts\evalDesigns_SMPMSM_example2.m, which is used by the optimization algorithm 
% for processing generated designs and calculating the objective values. 

%% Step 1: Specify initial design mxp-file and mat-file name to save the results
cd ../
initMXPscriptingAPI;   % MOTORXP-MATLAB API initialization
initdesignfile = getpmpath('SimFiles\OptimizationBaseDesign\BaseDesign12s14pOutrunner.mxp');
save2filename = 'Optimization_PMSM_outrunner_example2.mat';             % save optimization algorithm results to this mat-file

%% Step 2: Specify geometry constraints and initial design parameters 

% Inrunner or outrunner? Uncomment one of the following:
% motortype='InnerRotor';                 % inrunner
motortype='OuterRotor';                 % outrunner

% Coil fill factor
coilFillFactor=0.35;                    % coil fill factor in the range 0... 1

% Motor or generator? Uncomment one of the following:
machineMode='motor';                    % motor
% machineMode='generator';                % generator

% Operating conditions the machine is optimized for
targetSpeed=3000;                       % speed [RPM] the optimization is run for
targetPower=1.8;                        % output power [kW] the optimization is run for

% Outer diameter in millimeters (for fixed outer diameter specify outerDiameter_min = outerDiameter_max)
outerDiameter_min = 90.9;
outerDiameter_max = 90.9;

% Air gap length in millimeters (for fixed air gap specify airGap_min = airGap_max)
airGap_min = 0.5;
airGap_max = 0.5;

% Lamination length in millimeters (for fixed lamination length specify laminationLength_min = laminationLength_max)
laminationLength_min = 20;
laminationLength_max = 28;

% Inner diameter in millimeters (for fixed inner diameter specify innerDiameter_min = innerDiameter_max)
innerDiameter_min = 31;
innerDiameter_max = 31;

% Slot opening depth in millimeters 
slotopeningDepth = 1;

% Reference machine design weight (grams) and losses (W); reference design will be displayed as a red x on Pareto plot
refWeight = 986;     % grams
refLoss = 134.48;    % W
% If there is no reference design, uncomment the following 2 lines:
% refWeight = [];
% refLoss = [];

% Penalize designs whose losses exceed the specified loss threshold (efficiency less than 92.2%) to
% guide the search process toward finding designs with less losses (higher efficiencies)
penaltyLossThreshold = 140.625;    % Watt
%% Step 3: Specify number of designs generated by the optimization algorithm

maxNumberOfProcesses = feature('numcores');                      % maximum number of processes working in parallel (equal to the number of physical cpu cores)
% maxNumberOfProcesses = 7;                                        % or can be defined manually
init_dataset_size = 50;                                          % number of initial designs generated using latin hypercube sampling
NoOfBachSequential = 14;                                         % number of designs per one iteration of optimization algorithm 
niter = 50;                                                      % number of optimization algorithm iterations
maxeval = init_dataset_size+niter*NoOfBachSequential;            % total number of designs generated (50+50*14=750 designs by default)

%% Step 4: Specify optimization problem and run the optimization

designFunction = @evalDesigns_SMPMSM_example2;                   % funtion to process the designs generated by the optimization algorithm
no_outputs = 2;                                                  % number of optimization objectives
labelObjective = {'Weight, grams', 'Losses, W'};                 % optimization objectives

% Define bounds on design variables
bounds = [ % lower   upper  
             4          8;                       % 1  Tooth width
             0.3      0.8;                       % 2  Stator back iron depth ratio to tooth width
             0.8      1.2;                       % 3  Rotor back iron depth to stator back iron depth ratio
             3          6;                       % 4  Slot opening width
             15        25;                       % 5  Tooth tip angle
             1.5        3;                       % 6  Magnet depth
             110      170];                      % 7  Magnet Angle   
         
index = size(bounds,1)+1;   % design variable bounds index in "bounds"             
if outerDiameter_min==outerDiameter_max
    % fixed outer diameter
    Userdata.index_outerDiameter = 0;
    Userdata.outerDiameter = outerDiameter_min;
else
    % variable outer diameter
    Userdata.index_outerDiameter = index;
    Userdata.outerDiameter = [];
    bounds = [bounds;
              [outerDiameter_min outerDiameter_max]];   % add bounds for outer diameter
    index = index+1;
end

if airGap_min==airGap_max
    % fixed air gap length
    Userdata.index_airGap = 0;
    Userdata.airGap = airGap_min;
else
    % variable air gap length
    Userdata.index_airGap = index;
    Userdata.airGap = [];
    bounds = [bounds;
              [airGap_min airGap_max]];   % add bounds for air gap length
    index = index+1;
end

if laminationLength_min==laminationLength_max
    % fixed lamination length
    Userdata.index_laminationLength = 0;
    Userdata.laminationLength = laminationLength_min;
else
    % variable lamination length
    Userdata.index_laminationLength = index;
    Userdata.laminationLength = [];
    bounds = [bounds;
              [laminationLength_min laminationLength_max]];   % add bounds for lamination length
    index = index+1;
end

if innerDiameter_min==innerDiameter_max
    % fixed inner diameter
    Userdata.index_innerDiameter = 0;
    Userdata.innerDiameter = innerDiameter_min;
else
    % variable inner diameter
    Userdata.index_innerDiameter = index;
    Userdata.innerDiameter = [];
    bounds = [bounds;
              [innerDiameter_min innerDiameter_max]];   % add bounds for inner diameter
end

% Default weight and losses for designs with failed assembling
errWeight = 11*pi*outerDiameter_max^2/4*laminationLength_max/100;
errLoss = 10*targetPower*1000;

Userdata.slotopeningDepth=slotopeningDepth;
Userdata.motortype=motortype;                               % either 'InnerRotor' or 'OuterRotor'
Userdata.coilFillFactor=coilFillFactor;                     % coil fill factor
Userdata.targetSpeed=targetSpeed;                           % speed [RPM] the optimization is run for
Userdata.targetPower=targetPower;                           % output power [kW] the optimization is run for
Userdata.machineMode=machineMode;                           % either 'motor' or 'generator'
Userdata.initCurrent=364;                                   % expected stator current for 1 turn, no parallel paths, to speed up the calculation
% Userdata.initCurrent=[];                                    % empty by default
Userdata.errWeight = errWeight;
Userdata.errLoss = errLoss;
Userdata.penaltyLossThreshold = penaltyLossThreshold;       % penalty loss threshold

lb = bounds(:,1)';                               % lower bounds [lb1,lb2,...]
ub = bounds(:,2)';                               % upper bounds [ub1,ub2,...]

y_refdesign=[refWeight refLoss];    % reference design motor weight (grams) and losses (W) @(targetPower, targetSpeed) - reference design red x on Pareto plot

runTSEMOptimizationpm(designFunction,initdesignfile,ub,lb,no_outputs,init_dataset_size,maxeval,niter,maxNumberOfProcesses,save2filename,y_refdesign,labelObjective,Userdata);


