├── .gitattributes
├── .idea
├── .gitignore
├── FreeTO.iml
├── inspectionProfiles
│ └── profiles_settings.xml
├── modules.xml
└── vcs.xml
├── FreeTO.m
├── HHs3D.m
├── HnHns3D.m
├── LICENSE
├── README.md
├── SEMDOT.m
├── SIMP.m
├── STLs
├── Fig1.png
├── Fig2.png
├── Fig3.png
├── Fig4.jpg
├── GE_domain.STL
├── GE_fixed.STL
├── GE_force.STL
├── L_domain.STL
├── L_fixed.STL
├── L_force.STL
├── air_brack_TO.stl
├── air_domain.STL
├── air_fixed.STL
├── air_force.STL
├── air_zfixed.STL
├── hand_TO.gif
├── hand_domain.stl
├── hand_fixed.stl
├── hand_force1.stl
├── hand_force2.stl
├── hand_force3.stl
├── hand_force4.stl
├── hand_force5.stl
├── lever_domain.STL
├── lever_fixed.STL
├── lever_force1.STL
├── lever_force2.STL
├── lever_zfixed.STL
├── quad_TO.stl
├── quad_domain.STL
├── quad_fixed.STL
├── quad_force1.STL
├── quad_force2.STL
├── quad_force3.STL
├── quad_xfixed.STL
└── quad_yfixed.STL
├── display_3Dsmooth.m
├── domainprep.m
├── domainstokeep.m
├── forcevec.m
├── geomeshini.m
├── intriangulation.m
├── lk_H8.m
├── smoothedge3D.m
├── stlgen.m
├── supportDOFs.m
└── symmetry.m
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/FreeTO.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/FreeTO.m:
--------------------------------------------------------------------------------
1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 | %%%% FreeTO - 3D Topology Optimization of Freeform Structures %%%
3 | %%%% Author: Osezua Ibhadode, March 2024 %%%%%%%%%
4 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 | function S = FreeTO(domain,force1,MeshControl,volfrac,varargin)
6 | %% Examples
7 | %FreeTO('STLs\GE_domain.stl','STLs\GE_force.stl',70,0.3,'fixed','STLs\GE_fixed.stl','force2','STLs\GE_force.stl','Fmagy',[0 -2000],'Fmagz',[1500 0],'YoungsModulus',210e9)
8 | %FreeTO('STLs\air_domain.stl','STLs\air_force.stl',90,0.2,'fixed','STLs\air_fixed.stl','zfixed','STLs\air_zfixed.stl','force2','STLs\air_force.stl','force3','STLs\air_force.stl','Fmagx',[1000 1324 0],'Fmagy',[0 -1324 -2500],'YoungsModulus',210e9,'Symmetry1',"x-y",'direction1',"right",'optimization','SEMDOT','modelName','STLs\air_brack_TO.stl')
9 | %FreeTO('STLs\hand_domain.stl','STLs\hand_force1.stl',90,0.3,'fixed','STLs\hand_fixed.stl','force2','STLs\hand_force2.stl','force3','STLs\hand_force3.stl','force4','STLs\hand_force4.stl','force5','STLs\hand_force5.stl','Fmagz',2e3*ones(1,5),'YoungsModulus',210e9)
10 | %FreeTO('STLs\quad_domain.stl','STLs\quad_force1.stl',70,0.3,'fixed','STLs\quad_fixed.stl','xfixed','STLs\quad_xfixed.stl','yfixed','STLs\quad_yfixed.stl','force2','STLs\quad_force2.stl','force3','STLs\quad_force3.stl','Fmagz',[-1500 -1500 -1000],'YoungsModulus',2e9,'Symmetry1','y-z','Symmetry2','z-x','direction1','right','direction2','left','modelName','STLs\quad_TO.stl','keep_BCz','yes')
11 |
12 | %% Default values of parameters
13 | default_fix = []; default_xfix = []; default_yfix = []; default_zfix = [];
14 | default_for2 = []; default_for3 = []; default_for4 = []; default_for5 = [];
15 | default_for6 = []; default_for7 = []; default_for8 = []; default_for9 = [];
16 | default_for10 = []; default_keepdom = [];
17 | default_keep_BC = 'yes'; default_keep_BCx = 'no'; default_keep_BCy = 'no'; default_keep_BCz = 'no'; default_E0 = 1;
18 | default_penal = 3; default_rmin = 1.5; default_Fmagx = 0; default_Fmagy = 0; default_Fmagz = 0;
19 | default_text = []; default_load = 'distributed';
20 | default_sym1 = []; default_dir1 = 'right'; default_sym2 = []; default_dir2 = 'right'; default_sym3 = []; default_dir3 = 'right';
21 | default_v = 0.3; default_opt_type = 'SIMP';
22 |
23 | %% Input Parser for required, optional and name-value parameters
24 | pp = inputParser;
25 | addRequired(pp,'domain'); addRequired(pp,'force1'); addRequired(pp,'MeshControl'); addRequired(pp,'volfrac');
26 | addOptional(pp,'fixed',default_fix); addOptional(pp,'xfixed',default_xfix);
27 | addOptional(pp,'yfixed',default_yfix); addOptional(pp,'zfixed',default_zfix);
28 | addOptional(pp,'force2',default_for2); addOptional(pp,'force3',default_for3);
29 | addOptional(pp,'force4',default_for4); addOptional(pp,'force5',default_for5);
30 | addOptional(pp,'force6',default_for6); addOptional(pp,'force7',default_for7);
31 | addOptional(pp,'force8',default_for8); addOptional(pp,'force9',default_for9);
32 | addOptional(pp,'force10',default_for10); addOptional(pp,'keepdom',default_keepdom);
33 | addParameter(pp,'keep_BC',default_keep_BC); addParameter(pp,'keep_BCx',default_keep_BCx);
34 | addParameter(pp,'keep_BCy',default_keep_BCy); addParameter(pp,'keep_BCz',default_keep_BCz);
35 | addParameter(pp,'YoungsModulus',default_E0); addParameter(pp,'optimization',default_opt_type);
36 | addParameter(pp,'penaltySIMP',default_penal); addParameter(pp,'filterRadius',default_rmin);
37 | addParameter(pp,'Fmagx',default_Fmagx); addParameter(pp,'Fmagy',default_Fmagy);
38 | addParameter(pp,'Fmagz',default_Fmagz); addParameter(pp,'modelName',default_text);
39 | addParameter(pp,'loadtype',default_load); addParameter(pp,'PoissonRatio',default_v);
40 | addParameter(pp,'Symmetry1',default_sym1); addParameter(pp,'direction1',default_dir1);
41 | addParameter(pp,'Symmetry2',default_sym2); addParameter(pp,'direction2',default_dir2);
42 | addParameter(pp,'Symmetry3',default_sym3); addParameter(pp,'direction3',default_dir3);
43 |
44 | parse(pp,domain,force1,MeshControl,volfrac,varargin{:});
45 |
46 | %% Domain Initialization
47 | domain = pp.Results.domain; MeshControl = pp.Results.MeshControl;
48 |
49 | %% Optimization parameters
50 | volfrac = pp.Results.volfrac; penal = pp.Results.penaltySIMP;
51 | rmin = pp.Results.filterRadius; E0 = pp.Results.YoungsModulus;v = pp.Results.PoissonRatio;
52 | opt_type = pp.Results.optimization;
53 |
54 | %% Load and boundary conditions
55 | fixed = pp.Results.fixed; xfixed = pp.Results.xfixed;
56 | yfixed = pp.Results.yfixed; zfixed = pp.Results.zfixed;
57 | F1 = pp.Results.force1; F2 = pp.Results.force2; F3 = pp.Results.force3; F4 = pp.Results.force4;
58 | F5 = pp.Results.force5; F6 = pp.Results.force6; F7 = pp.Results.force7; F8 = pp.Results.force8;
59 | F9 = pp.Results.force9; F10 = pp.Results.force10; keep_domain = pp.Results.keepdom;
60 | Fmagx = pp.Results.Fmagx; Fmagy = pp.Results.Fmagy; Fmagz = pp.Results.Fmagz; loadtype = pp.Results.loadtype;
61 | keep_BC = pp.Results.keep_BC; keep_BCxyz = cellstr([string(pp.Results.keep_BCx) string(pp.Results.keep_BCy) string(pp.Results.keep_BCz)]);
62 |
63 | %% Post-processing parameters
64 | nm = pp.Results.modelName;
65 | symm = cellstr([string(pp.Results.Symmetry1) string(pp.Results.Symmetry2) string(pp.Results.Symmetry3)]);
66 | dir = cellstr([string(pp.Results.direction1) string(pp.Results.direction2) string(pp.Results.direction3)]);
67 |
68 | %% Check input
69 | if nargin == 4
70 | error('Please check that you included all required inputs in the right order and at least one support condition')
71 | elseif isempty(fixed) && isempty(xfixed) && isempty(yfixed) && isempty(zfixed)
72 | error('Please include at least one support condition')
73 | elseif all([Fmagx Fmagy Fmagz])
74 | error('Please include at least one non-zero load definition')
75 | end
76 |
77 | %% Run topology optimization
78 | if strcmpi(opt_type,'SIMP')
79 | % SIMP density-based
80 | [nelx,nely,nelz,ngrid,~,xg,top,lss,fnx,fny,fnz,dx,dy,dz,S] = SIMP(MeshControl,domain,fixed,xfixed,yfixed,...
81 | zfixed,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,keep_domain,keep_BC,keep_BCxyz,...
82 | volfrac,E0,v,penal,rmin,Fmagx,Fmagy,Fmagz,loadtype);
83 | elseif strcmpi(opt_type,'SEMDOT')
84 | % SEMDOT density-based
85 | [nelx,nely,nelz,ngrid,~,xg,top,lss,fnx,fny,fnz,dx,dy,dz,S] = SEMDOT(MeshControl,domain,fixed,xfixed,yfixed,...
86 | zfixed,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,keep_domain,keep_BC,keep_BCxyz,...
87 | volfrac,E0,v,rmin,Fmagx,Fmagy,Fmagz,loadtype);
88 | end
89 |
90 | %% Post-processing
91 | if ~isempty(symm)
92 | [xg,top,fnx,fny,fnz,nelx,nely,nelz,dx,dy,dz] = symmetry(xg,lss,nelx,nely,nelz,dx,dy,dz,ngrid,symm{1},dir{1});
93 | if length(symm) >= 2
94 | [xg,top,fnx,fny,fnz,nelx,nely,nelz,dx,dy,dz] = symmetry(xg,lss,nelx,nely,nelz,dx,dy,dz,ngrid,symm{2},dir{2});
95 | if length(symm) == 3
96 | [xg,top,fnx,fny,fnz,~,~,~,dx,dy,dz] = symmetry(xg,lss,nelx,nely,nelz,dx,dy,dz,ngrid,symm{3},dir{3});
97 | end
98 | end
99 | figure (1)
100 | display_3Dsmooth(xg,top);
101 | end
102 | if ~isempty(nm)
103 | stlgen(top,fnx,fny,fnz,dx,dy,dz,nm)
104 | end
105 | end
106 | % This Matlab code was written by Osezua Ibhadode % %
107 | % Please sent your comments to: ibhadode@ualberta.ca %
108 | % %
109 | % The code is intended for educational purposes and theoretical details %
110 | % are discussed in a paper which is currently under review %
111 | % %
112 | % Disclaimer: %
113 | % The author reserves all rights but do not guarantee that the code is %
114 | % free from errors. Furthermore, the author shall not be liable in any %
115 | % event caused by the use of the program. %
116 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117 |
--------------------------------------------------------------------------------
/HHs3D.m:
--------------------------------------------------------------------------------
1 | function [H,Hs]=HHs3D(nelx,nely,nelz,rmin,ele,nele)
2 | iH = ones(nele*(2*(ceil(rmin)-1)+1)^2,1);
3 | jH = ones(size(iH));
4 | sH = zeros(size(iH));
5 | k = 0;
6 | for k1 = 1:nelz
7 | for i1 = 1:nelx
8 | for j1 = 1:nely
9 | e1 = (k1-1)*nelx*nely + (i1-1)*nely+j1;
10 | for k2 = max(k1-(ceil(rmin)-1),1):min(k1+(ceil(rmin)-1),nelz)
11 | for i2 = max(i1-(ceil(rmin)-1),1):min(i1+(ceil(rmin)-1),nelx)
12 | for j2 = max(j1-(ceil(rmin)-1),1):min(j1+(ceil(rmin)-1),nely)
13 | e2 = (k2-1)*nelx*nely + (i2-1)*nely+j2;
14 | k = k+1; iH(k) = e1; jH(k) = e2;
15 | sH(k) = max(0,rmin-sqrt((i1-i2)^2+(j1-j2)^2+(k1-k2)^2));
16 | end
17 | end
18 | end
19 | end
20 | end
21 | end
22 | H = sparse(iH,jH,sH); H = H(ele,ele); Hs = sum(H,2);
--------------------------------------------------------------------------------
/HnHns3D.m:
--------------------------------------------------------------------------------
1 | function [Hn,Hns]=HnHns3D(nelx,nely,nelz,rnmin)
2 | inH = ones((nelx+1)*(nely+1)*(nelz+1)*(2*(ceil(rnmin)+1))^2,1);
3 | jnH = ones(size(inH)); snH = zeros(size(inH)); kn = 0;
4 | [elex,eley,elez] = meshgrid(1.5:nelx+0.5,1.5:nely+0.5,1.5:nelz+0.5);
5 | for kn1 = 1:nelz+1
6 | for in1 = 1:nelx+1
7 | for jn1 = 1:nely+1
8 | en1 = (kn1-1)*(nelx+1)*(nely+1)+(in1-1)*(nely+1)+jn1;
9 | for kn2 = max(kn1-(ceil(rnmin)),1):min(kn1+(ceil(rnmin)-1),nelz)
10 | for in2 = max(in1-(ceil(rnmin)),1):min(in1+(ceil(rnmin)-1),nelx)
11 | for jn2 = max(jn1-(ceil(rnmin)),1):min(jn1+(ceil(rnmin)-1),nely)
12 | en2 = (kn2-1)*nelx*nely + (in2-1)*nely+jn2;
13 | kn = kn+1; inH(kn) = en1; jnH(kn) = en2;
14 | snH(kn) = max(0,rnmin-sqrt((in1-elex(jn2,in2,kn2))^2+(jn1-eley(jn2,in2,kn2))^2+(kn1-elez(jn2,in2,kn2))^2));
15 | end
16 | end
17 | end
18 | end
19 | end
20 | end
21 | Hn = sparse(inH,jnH,snH); Hns = sum(Hn,2);
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 CADmaniac
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FreeTO
2 |
3 | **FreeTO** stands for Freeform Topology Optimization (3D topology optimization through a structured mesh with smooth boundaries)
4 | and is an open-source Matlab code for initializing, optimizing, and post-processing free-form 3D topology optimization problems.
5 |
6 |
7 |
8 | ## Syntax
9 | * **FreeTO(*file*, *force1*, *MeshControl*, *volfrac*, 'PropertyName', VALUE,...)** Performs topology optimization on the STL domain provided in *file* with the load-carrying STL subdomain provided in *force1*, *MeshControl* to create a structured hexahedral mesh, *volfrac* for the required volume fraction, property names and values (support conditions and force magnitudes are essential), and other default parameters. The property name-value inputs are given in Table 1.
10 |
11 | ### Table 1: Name-value inputs
12 |
13 | --------------------------------------------------------------------------------------------------------------------
14 | | Name-value | Description | Default value |
15 | |-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|---------------|
16 | | fixed | Mesh file (.stl) of the regions in domain with a Dirichlet displacement boundary condition fixed in all three directions | - |
17 | | xfixed, yfixed, zfixed | Type of topology optimization approach | - |
18 | | force2 – force10 | Mesh files (.stl) of regions in domain that carry up to 9 additional load cases | - |
19 | | keepdom | Mesh file (.stl) of regions in domain that should remain unchanged throughout the optimization | - |
20 | | keep_BC | Specify if the load and support (fixed in all directions) regions should be included in the optimized structure | Yes |
21 | | keep_BCx, keep_BCy, keep_BCz | Specify if the support regions fixed in x, y, and z directions, respectively, should be included in the optimized structure | No |
22 | | YoungsModulus | Specify the Young’s Modulus of the material |
23 | | PoissonsRatio | Specifies the Poisson’s ratio of the material | 0.3 |
24 | | optimization | Specify the optimization method (SIMP or SEMDOT) | SIMP |
25 | | Fmagx, Fmagy, Fmagz | Indicates the x, y, and z components of the loads | 0, 0, 0 |
26 | | modelName | Indicates the name of the mesh file (.stl) generated from the optimized structure | - |
27 | | loadtype | Indicates if a load should be applied at a point (center node) or distributed across all nodes in a load case | distributed |
28 | | Symmetry1, Symmetry2, Symmetry3 | Indicates a symmetry plane to mirror the optimized topology. Symmetry can be indicated a maximum of 3 times. | - |
29 | | direction1, direction2, direction3 | Indicates whether the mirror should occur to the left or right of the symmetry plane. It can be invoked the same number of times as Symmetry | Right |
30 |
31 | ### Table 2: Outputs
32 | | Variable | Description |
33 | |----------|---------------------------------------------------------|
34 | | comp | Compliance of optimized topology |
35 | | finalvol | Volume fraction of optimized topology |
36 | | eleden | Element density array |
37 | | gridden | Grid density array |
38 | | elenum1 | Number of active elements in the optimization |
39 | | elenum2 | Total number of elements (active + passive) |
40 | | | Display of the optimized topology |
41 | | | Display of the compliance and volume fraction histories |
42 | | | STL file (optional) |
43 |
44 | ## Examples:
45 |
46 | The following examples show how **FreeTO** is used.
47 | Input STL files of the sample design problems have been prepared and are in the STLs folder in this repository. The input file preparation is shown in a video for Example 1 [here](https://1drv.ms/v/s!ArlEZ0UGGKnchvZ0yWGqPRQcVgRg1Q?e=mK8vHb).
48 |
49 | * Example 1:
50 | Optimize a GE bracket given the freebody diagram on the left of Figure 1
51 |
52 | - **FreeTO('STLs\GE_domain.stl','STLs\GE_force.stl',80,0.3,'fixed','STLs\GE_fixed.stl','force2','STLs\GE_force.stl','Fmagy',[0 -2000],'Fmagz',[1500 0],'YoungsModulus',210e9)**
53 |
54 |
55 |
56 | * Example 2:
57 | Optimize one half of an airplane bracket
58 |
59 | - **FreeTO('STLs\air_domain.stl','STLs\air_force.stl',90,0.2,'fixed','STLs\air_fixed.stl','zfixed','STLs\air_zfixed.stl','force2','STLs\air_force.stl','force3','STLs\air_force.stl','Fmagx',[1000 1324 0],'Fmagy',[0 -1324 -2500],'YoungsModulus',210e9,'Symmetry1',"x-y",'direction1',"right",'optimization','SEMDOT','modelName','STLs\air_brack_TO.stl')**
60 |
61 |
62 |
63 | * Example 3:
64 | Optimize a human hand model with loads on the fingertips
65 |
66 | - **FreeTO('STLs\hand_domain.stl','STLs\hand_force1.stl',90,0.3,'fixed','STLs\hand_fixed.stl','force2','STLs\hand_force2.stl','force3','STLs\hand_force3.stl','force4','STLs\hand_force4.stl','force5','STLs\hand_force5.stl','Fmagz',2e3*ones(1,5),'YoungsModulus',210e9)**
67 |
68 |
69 |
70 | * Example 4:
71 | Optimize the quarter of a quadcopter
72 |
73 | - **FreeTO('STLs\quad_domain.stl','STLs\quad_force1.stl',70,0.3,'fixed','STLs\quad_fixed.stl','xfixed','STLs\quad_xfixed.stl','yfixed','STLs\quad_yfixed.stl','force2','STLs\quad_force2.stl','force3','STLs\quad_force3.stl','Fmagz',[-1500 -1500 -1000],'YoungsModulus',2e9,'Symmetry1','y-z','Symmetry2','z-x','direction1','right','direction2','left','modelName','STLs\quad_TO.stl','keep_BCz','yes')**
74 |
75 |
76 |
77 |
78 | ## Supporting Open-Source Codes
79 | **FreeTO** utilizes other open-source codes such as [intriangulation.m](https://www.mathworks.com/matlabcentral/fileexchange/43381-intriangulation-vertices-faces-testp-heavytest) by Johannes Korsawe, and modifications to [top3D.m](https://www.top3d.app/) by Liu and Tovar, [SEMDOT.m](https://blogs.deakin.edu.au/dot/software/) by Fu et al., and [phi2stl.m](https://asmedigitalcollection.asme.org/computingengineering/article/17/4/041012/474348/An-Open-Source-Framework-for-Integrated-Additive) by Vogiatzis et al. FreeTO on this repository uses the optimality criteria method (OCM) but works much better with the Method of Moving Asymptotes (MMA) as optimizer. The implementation of MMA is given in SIMP.m and SEMDOT.m but the lines are commented out as the codes are not on this repository and the user should request them from [Prof. Krista Svanberg](https://people.kth.se/~krille/Welcome.html) by email. If using MMA, comment out lines 79 to 84, 135, 137 and uncomment lines 44 to 56, 86 to 99 in SEMDOT.m and SIMP.m. Furthermore, in SEMDOT.m and SIMP.m, tolx = tol_thresh = 1e-3, beta = ER = 0.5 are recommended values for MMA.
80 |
81 | ## To Cite
82 | If you find this code helpful in your work, please cite [this open access paper](https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4876754)
83 |
--------------------------------------------------------------------------------
/SEMDOT.m:
--------------------------------------------------------------------------------
1 | function [nelx,nely,nelz,ngrid,stp1,xg,top,lss,fnx,fny,fnz,del_x,del_y,del_z,S] = SEMDOT(MeshControl,domain,fixed,fixed_x,fixed_y,fixed_z,force_1,...
2 | force_2,force_3,force_4,force_5,force_6,force_7,force_8,force_9,force_10,keep_domain,...
3 | keep_BC,keep_BCxyz,vol,E00,nu,rmin,Fmagx,Fmagy,Fmagz,loadtype)
4 | %% Arbitrary Domains
5 | [~,oute,outeM,sup_all,sup_x,sup_y,sup_z,Fn,nelx,nely,nelz,nele,ndof,stp1,aa,del_x,del_y,del_z] = geomeshini(MeshControl,domain,fixed,fixed_x,...
6 | fixed_y,fixed_z,force_1,force_2,force_3,force_4,force_5,force_6,force_7,force_8,force_9,force_10,keep_domain,keep_BC,keep_BCxyz);
7 | % node and DOF connectivity matrix
8 | [~,~,~,~,edofMatn,nnele,ele,n_vec,~,MusD]...
9 | = domainprep(oute,outeM,vol,nelx,nely,nelz,nele);
10 | % force nodes
11 | [F,nf] = forcevec(Fn,ndof,Fmagx,Fmagy,Fmagz,loadtype);
12 | % fixed DOFs
13 | fixeddof = supportDOFs(sup_all,sup_x,sup_y,sup_z);
14 | %% USER-DEFINED LOOP PARAMETERS
15 | maxloop = 500; % Maximum number of iterations
16 | tolx = 0.003; % Terminarion criterion
17 | %% USER-DEFINED MATERIAL PROPERTIES
18 | E0 = 1*E00; % Young's modulus of solid material
19 | Emin = 0.001; % Young's modulus of void-like material
20 | tol = 1; tol_thresh = 3e-3;
21 | %% USER-DEFINED GRID POINTS
22 | ngrid=4; rnmin=1;
23 | %% INITIALIZE HEAVISIDE REGULARIZATION PARAMETER
24 | beta=0.1; ER=0.05;
25 | %% ELEMENTAL NODES AND COORDINATES
26 | [nodex,nodey,nodez] = meshgrid(0:nelx,0:nely,0:nelz);
27 | [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx,0:1/ngrid:nely,0:1/ngrid:nelz);
28 | %% USER-DEFINED LOAD DOFs
29 | %% Load domain
30 | U = zeros(ndof,nf);
31 | freedofs = setdiff(n_vec,fixeddof); % make a change here
32 | KE = (aa/0.5)*lk_H8(nu);
33 | iK = reshape(kron(edofMatn,ones(24,1))',24*24*nnele,1);
34 | jK = reshape(kron(edofMatn,ones(1,24))',24*24*nnele,1);
35 | %% PREPARE FILTER
36 | [H,Hs]=HHs3D(nelx,nely,nelz,rmin,ele,nele);
37 | %% PREPARE FILTER FOR NODELS
38 | [Hn,Hns]=HnHns3D(nelx,nely,nelz,rnmin);
39 | %% INITIALIZE ITERATION
40 | vx = repmat(vol,[nely,nelx,nelz]); vx = vx(:); vx = vx(ele); % make a change here
41 | vxPhys = vx;
42 | loop = 0;
43 | change = 1;
44 | % %% INITIALIZE MMA OPTIMIZER
45 | % m = 1; % The number of general constraints.
46 | % n = nnele; % The number of design variables x_j. % make a change here
47 | % xmin = zeros(n,1); % Column vector with the lower bounds for the variables x_j.
48 | % xmax = ones(n,1); % Column vector with the upper bounds for the variables x_j.
49 | % xold1 = vx(:); % xval, one iteration ago (provided that iter>1).
50 | % xold2 = vx(:); % xval, two iterations ago (provided that iter>2).
51 | % low = ones(n,1); % Column vector with the lower asymptotes from the previous iteration (provided that iter>1).
52 | % upp = ones(n,1); % Column vector with the upper asymptotes from the previous iteration (provided that iter>1).
53 | % a0 = 1; % The constants a_0 in the term a_0*z.
54 | % a = zeros(m,1); % Column vector with the constants a_i in the terms a_i*z.
55 | % c_MMA = 10000*ones(m,1); % Column vector with the constants c_i in the terms c_i*y_i.
56 | % d = zeros(m,1); % Column vector with the constants d_i in the terms 0.5*d_i*(y_i)^2.
57 | %% START ITERATION
58 | while (change > tolx && tol>tol_thresh) && loop < maxloop
59 | %% UPDATE ITERATION
60 | loop = loop+1;
61 | %% FE-ANALYSIS
62 | sK = KE(:)*(vxPhys(:)'*E0+(1-vxPhys(:))'*(Emin*E0)); % make a change here
63 | K = sparse(iK(:),jK(:),sK(:)); K = (K+K')/2;
64 | U(freedofs,:)=K(freedofs, freedofs)\F(freedofs,:);
65 | %% OBJECTIVE FUNCTION AND SENSITIVITY ANALYSIS
66 | ts_SA = tic;
67 | c = 0; dc = 0;
68 | for i = 1:size(F,2)
69 | Ui = U(:,i);
70 | ce = sum((Ui(edofMatn)*KE).*Ui(edofMatn),2); % make a change here
71 | c= c+sum((vxPhys.*E0+(1-vxPhys).*(Emin*E0)).*ce); % make a change here
72 | dc = dc-((1-vxPhys)*Emin+vxPhys).*E0.*ce;
73 | end
74 | dv = ones(nnele,1); cc(loop) = c; % make a change here
75 | %% FILTERING AND MODIFICATION OF SENSITIVITIES
76 | dc = H*(dc./Hs); % make a change here
77 | dv = H*(dv./Hs); % make a change here
78 | %% OPTIMALITY CRITERIA UPDATE
79 | l1 = 0; l2 = 1e9; move = 0.1;
80 | while (l2-l1)/(l1+l2) > 1e-3
81 | lmid = 0.5*(l2+l1);
82 | vxnew = max(0,max(vxPhys-move,min(1,min(vxPhys+move,vxPhys.*sqrt(-dc./dv/lmid)))));
83 | if sum(vxnew) > vol*nnele, l1 = lmid; else l2 = lmid; end
84 | end
85 | vxPhys = (H*vxnew)./Hs;
86 | % %% METHOD OF MOVING ASYMPTOTES
87 | % xval = vx; % make a change here
88 | % f0val = c;
89 | % df0dx = dc; % make a change here
90 | % fval = sum(vxPhys)/(vol*nnele) - 1; % make a change here
91 | % dfdx = dv' / (vol*nnele); % make a change here
92 | % [vxmma, ~, ~, ~, ~, ~, ~, ~, ~, low,upp] = ...
93 | % mmasub(m, n, loop, xval, xmin, xmax, xold1, xold2, ...
94 | % f0val,df0dx,fval,dfdx,low,upp,a0,a,c_MMA,d);
95 | % %% Update MMA Variables
96 | % vxnew = vxmma; % make a change here
97 | % vxPhys = (H*vxnew)./Hs; % make a change here
98 | % xold2 = xold1(:);
99 | % xold1 = vx(:);
100 | %% Change to total number of elements
101 | vxPhys1 = zeros(nely,nelx,nelz); vxPhys2 = vxPhys1(:); % make a change here
102 | vxPhys2(ele) = vxPhys; vxPhys = vxPhys2; vxPhys(MusD) = 1; % make a change here
103 | %% Apply smooth edge algorithm
104 | [vxPhys,xg,lss,top,tol] = smoothedge3D(vxPhys,Hn,Hns,nelx,nely,nelz,nele,nnele,nodex,nodey,nodez,fnx,fny,fnz,beta,ngrid);
105 | %% CHECK CONVERGENCE
106 | change = sum(abs(vxnew(:)-vx(:)))/(vol*nnele); % make a change here
107 | vx=vxnew;
108 | if (change <= tolx || tol<=tol_thresh) || loop >= maxloop
109 | vxPhys(MusD) = 1;
110 | [vxPhys,xg,lss,top,tol] = smoothedge3D(vxPhys,Hn,Hns,nelx,nely,nelz,nele,nnele,nodex,nodey,nodez,fnx,fny,fnz,beta,ngrid);
111 | end
112 | %% PRINT RESULTS
113 | fvol(loop) = sum(vxPhys(:))/(nnele);
114 | fprintf('It.:%5i Obj.:%11.3f Vol.:%7.3f ch.:%7.5f Topo.:%7.5f\n'...
115 | ,loop,cc(loop),fvol(loop),change,tol); % make a change here
116 | figure(1)
117 | clf;
118 | display_3Dsmooth(flip(xg,3),flip(top,3));
119 | hold on;
120 | figure(2)
121 | clf;
122 | yyaxis left
123 | plot(cc,'b-','LineWidth',1.8); % make a change here
124 | set(gca,'FontName','Times New Roman','Box','On','LineWidth',2,'FontSize',15,'defaultAxesColorOrder',[0 0 1; 1 0 0]);
125 | %plot(loop,cc(loop),'b*','LineWidth',2,'MarkerSize',8) % make a change here
126 | xlabel('Iteration','Interpreter','Latex')
127 | ylabel('Compliance (Nm)', 'rotation', 90,'Interpreter','Latex')
128 | ax = gca; ax.YColor = 'b';
129 |
130 | yyaxis right
131 | plot(fvol,'r-','LineWidth',1.8);
132 | ylabel('Volume fraction', 'rotation', 270,'Interpreter','Latex'); ax = gca; ax.YColor = 'r';
133 | pause(1e-6); hold off
134 | %% UPDATE% HEAVISIDE REGULARIZATION PARAMETER
135 | if beta < 2
136 | beta=beta+ER;
137 | end
138 | fprintf('Parameter beta increased to %g.\n',beta);
139 | vxPhys_full = reshape(vxPhys,nely,nelx,nelz);
140 | vxPhys = vxPhys(ele);
141 | end
142 | cc_end = cc(end); S = struct('comp',cc_end,'finalvol',fvol(end),'eleden',vxPhys_full,'gridden',xg,'elenum1',nnele,'elenum2',nele);
--------------------------------------------------------------------------------
/SIMP.m:
--------------------------------------------------------------------------------
1 | function [nelx,nely,nelz,ngrid,stp1,xg,top,lss,fnx,fny,fnz,del_x,del_y,del_z,S] = SIMP(MeshControl,domain,fixed,fixed_x,fixed_y,fixed_z,force_1,...
2 | force_2,force_3,force_4,force_5,force_6,force_7,force_8,force_9,force_10,keep_domain,...
3 | keep_BC,keep_BCxyz,vol,E00,nu,penal,rmin,Fmagx,Fmagy,Fmagz,loadtype)
4 | %% Arbitrary Domains
5 | [~,oute,outeM,sup_all,sup_x,sup_y,sup_z,Fn,nelx,nely,nelz,nele,ndof,stp1,aa,del_x,del_y,del_z] = geomeshini(MeshControl,domain,fixed,fixed_x,...
6 | fixed_y,fixed_z,force_1,force_2,force_3,force_4,force_5,force_6,force_7,force_8,force_9,force_10,keep_domain,keep_BC,keep_BCxyz);
7 | % node and DOF connectivity matrix
8 | [~,~,~,~,edofMatn,nnele,ele,alldofs,~,MusD]...
9 | = domainprep(oute,outeM,vol,nelx,nely,nelz,nele);
10 | % force nodes
11 | [F,nf] = forcevec(Fn,ndof,Fmagx,Fmagy,Fmagz,loadtype);
12 | % fixed DOFs
13 | fixeddof = supportDOFs(sup_all,sup_x,sup_y,sup_z);
14 | %% USER-DEFINED LOOP PARAMETERS
15 | maxloop = 500; % Maximum number of iterations
16 | tolx = 0.003; % Terminarion criterion
17 | %% USER-DEFINED MATERIAL PROPERTIES
18 | E0 = 1*E00; % Young's modulus of solid material
19 | Emin = 0.001; % Young's modulus of void-like material
20 | tol = 1; tol_thresh = 3e-3;
21 | %% USER-DEFINED GRID POINTS
22 | ngrid=4; rnmin=1;
23 | %% INITIALIZE HEAVISIDE REGULARIZATION PARAMETER
24 | beta=0.1; ER=0.05;
25 | %% ELEMENTAL NODES AND COORDINATES
26 | [nodex,nodey,nodez] = meshgrid(0:nelx,0:nely,0:nelz);
27 | [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx,0:1/ngrid:nely,0:1/ngrid:nelz);
28 | %% USER-DEFINED LOAD DOFs
29 | %% Load domain
30 | U = zeros(ndof,nf);
31 | freedofs = setdiff(alldofs,fixeddof); % make a change here
32 | KE = (aa/0.5)*lk_H8(nu);
33 | iK = reshape(kron(edofMatn,ones(24,1))',24*24*nnele,1);
34 | jK = reshape(kron(edofMatn,ones(1,24))',24*24*nnele,1);
35 | %% PREPARE FILTER
36 | [H,Hs]=HHs3D(nelx,nely,nelz,rmin,ele,nele);
37 | %% PREPARE FILTER FOR NODELS
38 | [Hn,Hns]=HnHns3D(nelx,nely,nelz,rnmin);
39 | %% INITIALIZE ITERATION
40 | vx = repmat(vol,[nely,nelx,nelz]); vx = vx(:); vx = vx(ele); % make a change here
41 | vxPhys = vx;
42 | loop = 0;
43 | change = 1;
44 | % %% INITIALIZE MMA OPTIMIZER
45 | % m = 1; % The number of general constraints.
46 | % n = nnele; % The number of design variables x_j. % make a change here
47 | % xmin = zeros(n,1); % Column vector with the lower bounds for the variables x_j.
48 | % xmax = ones(n,1); % Column vector with the upper bounds for the variables x_j.
49 | % xold1 = vx(:); % xval, one iteration ago (provided that iter>1).
50 | % xold2 = vx(:); % xval, two iterations ago (provided that iter>2).
51 | % low = ones(n,1); % Column vector with the lower asymptotes from the previous iteration (provided that iter>1).
52 | % upp = ones(n,1); % Column vector with the upper asymptotes from the previous iteration (provided that iter>1).
53 | % a0 = 1; % The constants a_0 in the term a_0*z.
54 | % a = zeros(m,1); % Column vector with the constants a_i in the terms a_i*z.
55 | % c_MMA = 10000*ones(m,1); % Column vector with the constants c_i in the terms c_i*y_i.
56 | % d = zeros(m,1); % Column vector with the constants d_i in the terms 0.5*d_i*(y_i)^2.
57 | %% START ITERATION
58 | while (change > tolx && tol>tol_thresh) && loop < maxloop
59 | %% UPDATE ITERATION
60 | loop = loop+1;
61 | %% FE-ANALYSIS
62 | Ee = Emin+vxPhys(:)'.^penal.*(E0-Emin);
63 | sK = KE(:)*Ee; % make a change here
64 | K = sparse(iK(:),jK(:),sK(:)); K = (K+K')/2;
65 | U(freedofs,:)=K(freedofs, freedofs)\F(freedofs,:);
66 | %% OBJECTIVE FUNCTION AND SENSITIVITY ANALYSIS
67 | c = 0; dc = 0;
68 | for i = 1:size(F,2)
69 | Ui = U(:,i);
70 | ce = sum((Ui(edofMatn)*KE).*Ui(edofMatn),2); % make a change here
71 | c= c+sum(Ee'.*ce); % make a change here
72 | dc = dc-penal.*vxPhys(:).^(penal-1).*(E0-Emin).*ce;
73 | end
74 | dv = ones(nnele,1); cc(loop) = c; % make a change here
75 | %% FILTERING AND MODIFICATION OF SENSITIVITIES
76 | dc = H*(dc./Hs); % make a change here
77 | dv = H*(dv./Hs); % make a change here
78 | %% OPTIMALITY CRITERIA UPDATE
79 | l1 = 0; l2 = 1e9; move = 0.1;
80 | while (l2-l1)/(l1+l2) > 1e-3
81 | lmid = 0.5*(l2+l1);
82 | vxnew = max(0,max(vxPhys-move,min(1,min(vxPhys+move,vxPhys.*sqrt(-dc./dv/lmid)))));
83 | if sum(vxnew) > vol*nnele, l1 = lmid; else l2 = lmid; end
84 | end
85 | vxPhys = (H*vxnew)./Hs;
86 | % %% METHOD OF MOVING ASYMPTOTES
87 | % xval = vx; % make a change here
88 | % f0val = c;
89 | % df0dx = dc; % make a change here
90 | % fval = sum(vxPhys)/(vol*nnele) - 1; % make a change here
91 | % dfdx = dv' / (vol*nnele); % make a change here
92 | % [vxmma, ~, ~, ~, ~, ~, ~, ~, ~, low,upp] = ...
93 | % mmasub(m, n, loop, xval, xmin, xmax, xold1, xold2, ...
94 | % f0val,df0dx,fval,dfdx,low,upp,a0,a,c_MMA,d);
95 | % %% Update MMA Variables
96 | % vxnew = vxmma; % make a change here
97 | % vxPhys = (H*vxnew)./Hs; % make a change here
98 | % xold2 = xold1(:);
99 | % xold1 = vx(:);
100 | %% Change to total number of elements
101 | vxPhys1 = zeros(nely,nelx,nelz); vxPhys2 = vxPhys1(:); % make a change here
102 | vxPhys2(ele) = vxPhys; vxPhys = vxPhys2; vxPhys(MusD) = 1; % make a change here
103 | %% Apply smooth edge algorithm
104 | [vxPhys,xg,lss,top,tol] = smoothedge3D(vxPhys,Hn,Hns,nelx,nely,nelz,nele,nnele,nodex,nodey,nodez,fnx,fny,fnz,beta,ngrid);
105 | %% CHECK CONVERGENCE
106 | change = sum(abs(vxnew(:)-vx(:)))/(vol*nnele); % make a change here
107 | vx=vxnew;
108 | if (change <= tolx || tol<=tol_thresh) || loop >= maxloop
109 | vxPhys(MusD) = 1;
110 | [vxPhys,xg,lss,top,tol] = smoothedge3D(vxPhys,Hn,Hns,nelx,nely,nelz,nele,nnele,nodex,nodey,nodez,fnx,fny,fnz,beta,ngrid);
111 | end
112 | %% PRINT RESULTS
113 | fvol(loop) = sum(vxPhys(:))/(nnele);
114 | fprintf('It.:%5i Obj.:%11.3f Vol.:%7.3f ch.:%7.5f Topo.:%7.5f\n'...
115 | ,loop,cc(loop),fvol(loop),change,tol); % make a change here
116 | figure(1);
117 | clf;
118 | display_3Dsmooth(flip(xg,3),flip(top,3));
119 | hold on;
120 | figure(2)
121 | clf;
122 | yyaxis left
123 | plot(cc,'b-','LineWidth',1.8); % make a change here
124 | set(gca,'FontName','Times New Roman','Box','On','LineWidth',2,'FontSize',15,'defaultAxesColorOrder',[0 0 1; 1 0 0]);
125 | %plot(loop,cc(loop),'b*','LineWidth',2,'MarkerSize',8) % make a change here
126 | xlabel('Iteration','Interpreter','Latex')
127 | ylabel('Compliance (Nm)', 'rotation', 90,'Interpreter','Latex')
128 | ax = gca; ax.YColor = 'b';
129 |
130 | yyaxis right
131 | plot(fvol,'r-','LineWidth',1.8);
132 | ylabel('Volume fraction', 'rotation', 270,'Interpreter','Latex'); ax = gca; ax.YColor = 'r';
133 | pause(1e-6); hold off
134 | %% UPDATE% HEAVISIDE REGULARIZATION PARAMETER
135 | if beta < 2
136 | beta=beta+ER;
137 | end
138 | fprintf('Parameter beta increased to %g.\n',beta);
139 | vxPhys_full = reshape(vxPhys,nely,nelx,nelz);
140 | vxPhys = vxPhys(ele);
141 | end
142 | cc_end = cc(end); S = struct('comp',cc_end,'finalvol',fvol(end),'eleden',vxPhys_full,'gridden',xg,'elenum1',nnele,'elenum2',nele);
--------------------------------------------------------------------------------
/STLs/Fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/Fig1.png
--------------------------------------------------------------------------------
/STLs/Fig2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/Fig2.png
--------------------------------------------------------------------------------
/STLs/Fig3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/Fig3.png
--------------------------------------------------------------------------------
/STLs/Fig4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/Fig4.jpg
--------------------------------------------------------------------------------
/STLs/GE_domain.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/GE_domain.STL
--------------------------------------------------------------------------------
/STLs/GE_fixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/GE_fixed.STL
--------------------------------------------------------------------------------
/STLs/GE_force.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/GE_force.STL
--------------------------------------------------------------------------------
/STLs/L_domain.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/L_domain.STL
--------------------------------------------------------------------------------
/STLs/L_fixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/L_fixed.STL
--------------------------------------------------------------------------------
/STLs/L_force.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/L_force.STL
--------------------------------------------------------------------------------
/STLs/air_brack_TO.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/air_brack_TO.stl
--------------------------------------------------------------------------------
/STLs/air_domain.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/air_domain.STL
--------------------------------------------------------------------------------
/STLs/air_fixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/air_fixed.STL
--------------------------------------------------------------------------------
/STLs/air_force.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/air_force.STL
--------------------------------------------------------------------------------
/STLs/air_zfixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/air_zfixed.STL
--------------------------------------------------------------------------------
/STLs/hand_TO.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_TO.gif
--------------------------------------------------------------------------------
/STLs/hand_domain.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_domain.stl
--------------------------------------------------------------------------------
/STLs/hand_fixed.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_fixed.stl
--------------------------------------------------------------------------------
/STLs/hand_force1.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_force1.stl
--------------------------------------------------------------------------------
/STLs/hand_force2.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_force2.stl
--------------------------------------------------------------------------------
/STLs/hand_force3.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_force3.stl
--------------------------------------------------------------------------------
/STLs/hand_force4.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_force4.stl
--------------------------------------------------------------------------------
/STLs/hand_force5.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/hand_force5.stl
--------------------------------------------------------------------------------
/STLs/lever_domain.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/lever_domain.STL
--------------------------------------------------------------------------------
/STLs/lever_fixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/lever_fixed.STL
--------------------------------------------------------------------------------
/STLs/lever_force1.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/lever_force1.STL
--------------------------------------------------------------------------------
/STLs/lever_force2.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/lever_force2.STL
--------------------------------------------------------------------------------
/STLs/lever_zfixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/lever_zfixed.STL
--------------------------------------------------------------------------------
/STLs/quad_TO.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_TO.stl
--------------------------------------------------------------------------------
/STLs/quad_domain.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_domain.STL
--------------------------------------------------------------------------------
/STLs/quad_fixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_fixed.STL
--------------------------------------------------------------------------------
/STLs/quad_force1.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_force1.STL
--------------------------------------------------------------------------------
/STLs/quad_force2.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_force2.STL
--------------------------------------------------------------------------------
/STLs/quad_force3.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_force3.STL
--------------------------------------------------------------------------------
/STLs/quad_xfixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_xfixed.STL
--------------------------------------------------------------------------------
/STLs/quad_yfixed.STL:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ooibhadode/FreeTO/96862eba84bbf4ddc04f6099ebfb548866d42c77/STLs/quad_yfixed.STL
--------------------------------------------------------------------------------
/display_3Dsmooth.m:
--------------------------------------------------------------------------------
1 | function display_3Dsmooth(xg,top)
2 | [nely,nelx,nelz] = size(xg);
3 | cla, hold on, view(30,30), rotate3d on, axis equal, axis([0 nelx 0 nely 0 nelz]), box
4 | set(gca,'YDir','reverse','ZDir','reverse','ZtickLabel',flipud(get(gca,'Ztick')'));
5 | [X,Y,Z] = meshgrid(1:nelx,1:nely,1:nelz);
6 | fcolor=[0 1 1];
7 | patch(isocaps(X,Y,Z,top,0),'FaceColor',fcolor,'EdgeColor','none');
8 | p = patch(isosurface(X,Y,Z,top,0),'FaceColor',fcolor,'EdgeColor','none');
9 | camlight('headlight')
10 | axis off;
11 | box off;
12 | set(gcf, 'color', [1 1 1]) %Background
13 | drawnow
14 | end
--------------------------------------------------------------------------------
/domainprep.m:
--------------------------------------------------------------------------------
1 | function [edofMat1,edofMat,ndn,nd,edofMatn,nnele,ele,n_vec,vol1,MusD]...
2 | = domainprep(oute,outeM,vol,nelx,nely,nelz,nele)
3 |
4 | %% Node (edofMat1) and element (edofMat) connectivity matrices
5 | nodenr = reshape(1:(1+nelx)*(1+nely)*(1+nelz),(1+nely),(1+nelx),(1+nelz)); % node numbers in domain
6 | nodenrs1 = nodenr-1; nodenrs1(end,:,:) = []; nodenrs1(:,end,:) = []; nodenrs1(:,:,end) = [];
7 | edofMat1 = nodenrs1(:) + [2 2+(nely+1) 2+nely 1 (nelx+1)*(nely+1)+2 (nelx+1)*(nely+1)+2+(nely+1) ...
8 | (nelx+1)*(nely+1)+2+nely (nelx+1)*(nely+1)+1]; % connectivity matrix for node numbers
9 | nodenrs = 3*(nodenr-1); nodenrs(end,:,:) = []; nodenrs(:,end,:) = []; nodenrs(:,:,end) = [];
10 | % element connectivity matrix
11 | edofMat = nodenrs(:) + [4 5 6 4+3*(nely+1) 5+3*(nely+1) 6+3*(nely+1) 1+3*(nely+1) 2+3*(nely+1) 3+3*(nely+1) ...
12 | 1 2 3 4+3*(nelx+1)*(nely+1) 5+3*(nelx+1)*(nely+1) 6+3*(nelx+1)*(nely+1) 4+3*(nelx+1)*(nely+1)+3*(nely+1)...
13 | 5+3*(nelx+1)*(nely+1)+3*(nely+1) 6+3*(nelx+1)*(nely+1)+3*(nely+1) 1+3*(nelx+1)*(nely+1)+3*(nely+1)...
14 | 2+3*(nelx+1)*(nely+1)+3*(nely+1) 3+3*(nelx+1)*(nely+1)+3*(nely+1) 1+3*(nelx+1)*(nely+1)...
15 | 2+3*(nelx+1)*(nely+1) 3+3*(nelx+1)*(nely+1)];
16 |
17 | %% List of important parameters needed for optimization
18 | ndn = find(oute(:) == 0); % vector of passive domain elements
19 | nd = length(ndn); % number of passive domain elements
20 | edofMatn = edofMat; edofMatn(ndn,:) = []; % connectivity matrix of active domain elements only
21 | nnele = length(edofMatn(:,1)); % number of active domain elements
22 | ele = setdiff(1:nele,ndn); % active domain element numbers from total domain element numbers
23 | n_vec = unique(edofMatn(:)); % degrees of freedom for active domain elements only
24 | vol1 = vol*(nnele/nele); % volume fraction based on active domains only
25 | outeM = outeM(:); MusD = find(outeM == 1);
26 |
--------------------------------------------------------------------------------
/domainstokeep.m:
--------------------------------------------------------------------------------
1 | function outeM = domainstokeep(oute,nelx,nely,nelz,keep_BC,keep_BCxyz,stp2,stp3,stp4,stp5,...
2 | stp6_1,stp7,stf2,stf3,stf4,stf5,stf6_1,stf7,nnf1,nnf2,x1_cen,y1_cen,z1_cen)
3 | %% Collect the vertices and faces of the boundary condition regions to keep during optimization
4 | if strcmp(keep_BC,'yes')
5 | % keep_BCxyz{1} = xfixed, keep_BCxyz{2} = yfixed, keep_BCxyz{3} = zfixed
6 | if strcmp(keep_BCxyz{1},'no') && strcmp(keep_BCxyz{2},'no') && strcmp(keep_BCxyz{3},'no')
7 | stpM = [stp2;stp6_1;stp7]; stfM = [stf2;stf6_1;stf7];
8 | nn1 = [size(stp2,1) nnf1 size(stp7,1)];
9 | nn2 = [size(stf2,1) nnf2 size(stf7,1)];
10 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
11 | elseif strcmp(keep_BCxyz{1},'yes') && strcmp(keep_BCxyz{2},'no') && strcmp(keep_BCxyz{3},'no')
12 | stpM = [stp2;stp3;stp6_1;stp7]; stfM = [stf2;stf3;stf6_1;stf7];
13 | nn1 = [size(stp2,1) size(stp3,1) nnf1 size(stp7,1)];
14 | nn2 = [size(stf2,1) size(stf3,1) nnf2 size(stf7,1)];
15 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
16 | elseif strcmp(keep_BCxyz{1},'no') && strcmp(keep_BCxyz{2},'yes') && strcmp(keep_BCxyz{3},'no')
17 | stpM = [stp2;stp4;stp6_1;stp7]; stfM = [stf2;stf4;stf6_1;stf7];
18 | nn1 = [size(stp2,1) size(stp4,1) nnf1 size(stp7,1)];
19 | nn2 = [size(stf2,1) size(stf4,1) nnf2 size(stf7,1)];
20 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
21 | elseif strcmp(keep_BCxyz{1},'no') && strcmp(keep_BCxyz{2},'no') && strcmp(keep_BCxyz{3},'yes')
22 | stpM = [stp2;stp5;stp6_1;stp7]; stfM = [stf2;stf5;stf6_1;stf7];
23 | nn1 = [size(stp2,1) size(stp5,1) nnf1 size(stp7,1)];
24 | nn2 = [size(stf2,1) size(stf5,1) nnf2 size(stf7,1)];
25 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
26 | elseif strcmp(keep_BCxyz{1},'yes') && strcmp(keep_BCxyz{2},'yes') && strcmp(keep_BCxyz{3},'no')
27 | stpM = [stp2;stp3;stp4;stp6_1;stp7]; stfM = [stf2;stf3;stf4;stf6_1;stf7];
28 | nn1 = [size(stp2,1) size(stp3,1) size(stp4,1) nnf1 size(stp7,1)];
29 | nn2 = [size(stf2,1) size(stf3,1) size(stf4,1) nnf2 size(stf7,1)];
30 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
31 | elseif strcmp(keep_BCxyz{1},'yes') && strcmp(keep_BCxyz{2},'no') && strcmp(keep_BCxyz{3},'yes')
32 | stpM = [stp2;stp3;stp5;stp6_1;stp7]; stfM = [stf2;stf3;stf5;stf6_1;stf7];
33 | nn1 = [size(stp2,1) size(stp3,1) size(stp5,1) nnf1 size(stp7,1)];
34 | nn2 = [size(stf2,1) size(stf3,1) size(stf5,1) nnf2 size(stf7,1)];
35 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
36 | elseif strcmp(keep_BCxyz{1},'no') && strcmp(keep_BCxyz{2},'yes') && strcmp(keep_BCxyz{3},'yes')
37 | stpM = [stp2;stp4;stp5;stp6_1;stp7]; stfM = [stf2;stf4;stf5;stf6_1;stf7];
38 | nn1 = [size(stp2,1) size(stp4,1) size(stp5,1) nnf1 size(stp7,1)];
39 | nn2 = [size(stf2,1) size(stf4,1) size(stf5,1) nnf2 size(stf7,1)];
40 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
41 | elseif strcmp(keep_BCxyz{1},'yes') && strcmp(keep_BCxyz{2},'yes') && strcmp(keep_BCxyz{3},'yes')
42 | stpM = [stp2;stp3;stp4;stp5;stp6_1;stp7]; stfM = [stf2;stf3;stf4;stf5;stf6_1;stf7];
43 | nn1 = [size(stp2,1) size(stp3,1) size(stp4,1) size(stp5,1) nnf1 size(stp7,1)];
44 | nn2 = [size(stf2,1) size(stf3,1) size(stf4,1) size(stf5,1) nnf2 size(stf7,1)];
45 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
46 | else
47 | stpM = [stp2;stp6_1;stp7]; stfM = [stf2;stf6_1;stf7];
48 | nn1 = [size(stp2,1) nnf1 size(stp7,1)];
49 | nn2 = [size(stf2,1) nnf2 size(stf7,1)];
50 | nn1(nn1 == 0) = []; nn2(nn2 == 0) = [];
51 | end
52 | else
53 | stpM = stp7; stfM = stf7; nn1 = size(stp7,1); nn2 = size(stf7,1);
54 | end
55 | % Identify elements according to the selected vertices and faces
56 | outeM = zeros(size(oute(:)));
57 | for i = 1:length(nn1)
58 | j1 = sum(nn1(1:i))-nn1(i)+1; k1 = j1+nn1(i)-1;
59 | j2 = sum(nn2(1:i))-nn2(i)+1; k2 = j2+nn2(i)-1;
60 | outeM = outeM+double(intriangulation(stpM(j1:k1,:),stfM(j2:k2,:),[x1_cen(:),y1_cen(:),z1_cen(:)]));
61 | outeM(outeM<0) = 0; outeM(outeM>1) = 1;
62 | end
63 | outeM = flip(reshape(outeM,nely,nelx,nelz),1);
--------------------------------------------------------------------------------
/forcevec.m:
--------------------------------------------------------------------------------
1 | function [F,nf] = forcevec(Fn,ndof,Fmagx,Fmagy,Fmagz,loadtype)
2 |
3 | nf = max([length(Fmagx) length(Fmagy) length(Fmagz)]);
4 | Fx = zeros(ndof,nf); Fy = zeros(ndof,nf); Fz = zeros(ndof,nf);
5 | for i = 1:nf
6 | frn = full(Fn(:,i)); frn(frn == 0) = [];
7 | if strcmp(loadtype,'point')
8 | frn = sort(frn); frn = frn(round(length(frn)/2));
9 | end
10 | frnm = [frn*3-2 frn*3-1 frn*3];
11 | if length(Fmagx) > 1
12 | Fx(frnm(:,1),i) = Fmagx(i)/length(frnm(:,1));
13 | else
14 | Fx(frnm(:,1),1) = Fmagx/length(frnm(:,1));
15 | end
16 | if length(Fmagy) > 1
17 | Fy(frnm(:,2),i) = Fmagy(i)/length(frnm(:,2));
18 | else
19 | Fy(frnm(:,2),1) = Fmagy/length(frnm(:,2));
20 | end
21 | if length(Fmagz) > 1
22 | Fz(frnm(:,3),i) = Fmagz(i)/length(frnm(:,3));
23 | else
24 | Fz(frnm(:,3),1) = Fmagz/length(frnm(:,3));
25 | end
26 | end
27 | F = Fx+Fy+Fz; F(:,all(F == 0)) = []; F = sparse(F);
--------------------------------------------------------------------------------
/geomeshini.m:
--------------------------------------------------------------------------------
1 | function [out_p,oute,outeM,sup_all,sup_x,sup_y,sup_z,Fn,nelx,nely,nelz,nele,ndof,stp1,a,...
2 | del_x,del_y,del_z] = geomeshini(MeshControl,inp1,inp2,inp3,...
3 | inp4,inp5,inp6,inp7,inp8,inp9,inp10,inp11,inp12,inp13,inp14,inp15,inp16,keep_BC,keep_BCxyz)
4 | inp_f = {inp6,inp7,inp8,inp9,inp10,inp11,inp12,inp13,inp14,inp15}; inp_f(~cellfun(@ischar,inp_f)) = [];
5 | % get stl vertices for inp1
6 | st1 = stlread(inp1); % read stl
7 | stp1 = st1.Points; stf1 = st1.ConnectivityList; % obtain vertices and faces
8 | % get bounding box
9 | stp_xmax = max(stp1(:,1)); stp_xmin = min(stp1(:,1)); % get the minimum and maximum x for domain
10 | del_x = stp_xmax-stp_xmin;
11 | stp_ymax = max(stp1(:,2)); stp_ymin = min(stp1(:,2)); % get the minimum and maximum y for domain
12 | del_y = stp_ymax-stp_ymin;
13 | stp_zmax = max(stp1(:,3)); stp_zmin = min(stp1(:,3)); % get the minimum and maximum z for domain
14 | del_z = stp_zmax-stp_zmin;
15 | stt = abs([stp_xmin stp_xmax stp_ymin stp_ymax stp_zmin stp_zmax]); % get the maximum of all maximums for domain
16 | stm = max(stt); stff = find(stt == stm(1)); % get the position of the max of all maxs
17 |
18 | if stff(1) == 1 || stff(1) == 2 % if the maximum is in position 1
19 | gpx = MeshControl;
20 | x_old = linspace(stp_xmin, stp_xmax, gpx); ssz_old = (x_old(2)-x_old(1))*1e-2;
21 | x = linspace(stp_xmin+ssz_old, stp_xmax-ssz_old, gpx);
22 | ssz = x(2)-x(1); gpx = length(x); a = ssz/2000; % the MeshControl should be defined from the x-axis
23 | y_old = stp_ymin:ssz:stp_ymax; diff_y = stp_ymax-y_old(end); % obtain y MeshControl
24 | y = stp_ymin+diff_y/2:ssz:stp_ymax; gpy = length(y);
25 | z_old = stp_zmin:ssz:stp_zmax; diff_z = stp_zmax-z_old(end); % obtain z MeshControl
26 | z = stp_zmin+diff_z/2:ssz:stp_zmax; gpz = length(z);
27 | x_cen = x+ssz/2; x_cen(end) = []; y_cen = y+ssz/2; y_cen(end) = []; z_cen = z+ssz/2; z_cen(end) = [];
28 | elseif stff(1) == 3 || stff(1) == 4
29 | gpy = MeshControl;
30 | y_old = linspace(stp_ymin, stp_ymax, gpy); ssz_old = (y_old(2)-y_old(1))*1e-2;
31 | y = linspace(stp_ymin+ssz_old, stp_ymax-ssz_old, gpy);
32 | ssz = y(2)-y(1); gpy = length(y); a = ssz/2000;
33 | x_old = stp_xmin:ssz:stp_xmax; diff_x = stp_xmax-x_old(end);
34 | x = stp_xmin+diff_x/2:ssz:stp_xmax; gpx = length(x);
35 | z_old = stp_zmin:ssz:stp_zmax; diff_z = stp_zmax-z_old(end);
36 | z = stp_zmin+diff_z/2:ssz:stp_zmax; gpz = length(z);
37 | x_cen = x+ssz/2; x_cen(end) = []; y_cen = y+ssz/2; y_cen(end) = []; z_cen = z+ssz/2; z_cen(end) = [];
38 | else
39 | gpz = MeshControl;
40 | z_old = linspace(stp_zmin, stp_zmax, gpz); ssz_old = (z_old(2)-z_old(1))*1e-2;
41 | z = linspace(stp_zmin+ssz_old,stp_zmax-ssz_old,gpz);
42 | ssz = z(2)-z(1); gpz = length(z); a = ssz/2000;
43 | x_old = stp_xmin:ssz:stp_xmax; diff_x = stp_xmax-x_old(end);
44 | x = stp_xmin+diff_x/2:ssz:stp_xmax; gpx = length(x);
45 | y_old = stp_ymin:ssz:stp_ymax; diff_y = stp_ymax-y_old(end); % obtain y MeshControl
46 | y = stp_ymin+diff_y/2:ssz:stp_ymax; gpy = length(y);
47 | x_cen = x+ssz/2; x_cen(end) = []; y_cen = y+ssz/2; y_cen(end) = []; z_cen = z+ssz/2; z_cen(end) = [];
48 | end
49 |
50 | %create meshgrid for x, y, and z
51 | [x1,y1,z1] = meshgrid(x,y,z); % create a meshgrid from x,y,z MeshControl
52 | [x1_cen,y1_cen,z1_cen] = meshgrid(x_cen,y_cen,z_cen);
53 | % for inp1 - Domain
54 | out = double(intriangulation(stp1,stf1,[x1(:),y1(:),z1(:)])); out(out<0) = 0; % check which points lie in and out of the domain
55 | % for inp2 - Fixed all DOFs support
56 | if ~isempty(inp2)
57 | st2 = stlread(inp2);
58 | stp2 = st2.Points; stf2 = st2.ConnectivityList;
59 | out2 = intriangulation(stp2,stf2,[x1(:),y1(:),z1(:)]);
60 | out2 = flip(reshape(out2,gpy,gpx,gpz),1);
61 | sup_all = find(out2(:)>0); % identify support nodes fixd in all directions in the domain
62 | else
63 | sup_all = []; stp2 = []; stf2 = [];
64 | end
65 | % for inp3 - Fixed in x
66 | if ~isempty(inp3)
67 | st3 = stlread(inp3);
68 | stp3 = st3.Points; stf3 = st3.ConnectivityList;
69 | out3 = intriangulation(stp3,stf3,[x1(:),y1(:),z1(:)]);
70 | out3 = flip(reshape(out3,gpy,gpx,gpz),1);
71 | sup_x = find(out3(:)>0);
72 | else
73 | sup_x = []; stp3 = []; stf3 = [];
74 | end
75 | % for inp4 - Fixed in y
76 | if ~isempty(inp4)
77 | st4 = stlread(inp4);
78 | stp4 = st4.Points; stf4 = st4.ConnectivityList;
79 | out4 = intriangulation(stp4,stf4,[x1(:),y1(:),z1(:)]);
80 | out4 = flip(reshape(out4,gpy,gpx,gpz),1);
81 | sup_y = find(out4(:)>0);
82 | else
83 | sup_y = []; stp4 = []; stf4 = [];
84 | end
85 | % for inp5 - Fixed in z
86 | if ~isempty(inp5)
87 | st5 = stlread(inp5);
88 | stp5 = st5.Points; stf5 = st5.ConnectivityList;
89 | out5 = intriangulation(stp5,stf5,[x1(:),y1(:),z1(:)]);
90 | out5 = flip(reshape(out5,gpy,gpx,gpz),1);
91 | sup_z = find(out5(:)>0);
92 | else
93 | sup_z = []; stp5 = []; stf5 = [];
94 | end
95 | % for inp6 - Force
96 | Fn = sparse(length(out),length(inp_f)); stp6_1 = []; stf6_1 = [];
97 | for i = 1:length(inp_f)
98 | st6 = stlread(inp_f{i});
99 | stp6 = st6.Points; stp6_1 = [stp6_1;stp6]; nnf1(i) = size(stp6,1);
100 | stf6 = st6.ConnectivityList; stf6_1 = [stf6_1;stf6]; nnf2(i) = size(stf6,1);
101 | out6 = intriangulation(stp6,stf6,[x1(:),y1(:),z1(:)]);
102 | out6 = flip(reshape(out6,gpy,gpx,gpz),1);
103 | Fn(1:length(find(out6(:)>0)),i) = find(out6(:)>0);
104 | end
105 | % for domains to keep
106 | if ~isempty(inp16)
107 | st7 = stlread(inp16);
108 | stp7 = st7.Points; stf7 = st7.ConnectivityList;
109 | out7 = intriangulation(stp7,stf7,[x1(:),y1(:),z1(:)]);
110 | out7 = flip(reshape(out7,gpy,gpx,gpz),1);
111 | dom_ke = find(out7(:)>0);
112 | else
113 | dom_ke = []; stp7 = []; stf7 = [];
114 | end
115 | out_p = flip(reshape(out,gpy,gpx,gpz),1); % flip the identified points
116 | nelx = size(out_p,2)-1; nely = size(out_p,1)-1; nelz = size(out_p,3)-1; nele = nelx*nely*nelz; % obtain nelx, nely,nelz and nele
117 | ndof = 3*(nelx+1)*(nely+1)*(nelz+1); % obtain number of degrees of freedom
118 | %% get elements in the domain
119 | oute = double(intriangulation(stp1,stf1,[x1_cen(:),y1_cen(:),z1_cen(:)])); oute(oute<0) = 0;
120 | oute = flip(reshape(oute,nely,nelx,nelz),1);
121 | %% get elements to keep during optimization
122 | outeM = domainstokeep(oute,nelx,nely,nelz,keep_BC,keep_BCxyz,stp2,stp3,stp4,stp5,...
123 | stp6_1,stp7,stf2,stf3,stf4,stf5,stf6_1,stf7,nnf1,nnf2,x1_cen,y1_cen,z1_cen);
--------------------------------------------------------------------------------
/intriangulation.m:
--------------------------------------------------------------------------------
1 | function in = intriangulation(vertices,faces,testp,heavytest)
2 | % intriangulation: Test points in 3d wether inside or outside a (closed) triangulation
3 | % usage: in = intriangulation(vertices,faces,testp,heavytest)
4 | %
5 | % arguments: (input)
6 | % vertices - points in 3d as matrix with three columns
7 | %
8 | % faces - description of triangles as matrix with three columns.
9 | % Each row contains three indices into the matrix of vertices
10 | % which gives the three cornerpoints of the triangle.
11 | %
12 | % testp - points in 3d as matrix with three columns
13 | %
14 | % heavytest - int n >= 0. Perform n additional randomized rotation tests.
15 | %
16 | % IMPORTANT: the set of vertices and faces has to form a watertight surface!
17 | %
18 | % arguments: (output)
19 | % in - a vector of length size(testp,1), containing 0 and 1.
20 | % in(nr) = 0: testp(nr,:) is outside the triangulation
21 | % in(nr) = 1: testp(nr,:) is inside the triangulation
22 | % in(nr) = -1: unable to decide for testp(nr,:)
23 | %
24 | % Thanks to Adam A for providing the FEX submission voxelise. The
25 | % algorithms of voxelise form the algorithmic kernel of intriangulation.
26 | %
27 | % Thanks to Sven to discussions about speed and avoiding problems in
28 | % special cases.
29 | %
30 | % Example usage:
31 | %
32 | % n = 10;
33 | % vertices = rand(n, 3)-0.5; % Generate random points
34 | % tetra = delaunayn(vertices); % Generate delaunay triangulization
35 | % faces = freeBoundary(TriRep(tetra,vertices)); % use free boundary as triangulation
36 | % n = 1000;
37 | % testp = 2*rand(n,3)-1; % Generate random testpoints
38 | % in = intriangulation(vertices,faces,testp);
39 | % % Plot results
40 | % h = trisurf(faces,vertices(:,1),vertices(:,2),vertices(:,3));
41 | % set(h,'FaceColor','black','FaceAlpha',1/3,'EdgeColor','none');
42 | % hold on;
43 | % plot3(testp(:,1),testp(:,2),testp(:,3),'b.');
44 | % plot3(testp(in==1,1),testp(in==1,2),testp(in==1,3),'ro');
45 | %
46 | % See also: intetrahedron, tsearchn, inpolygon
47 | %
48 | % Author: Johannes Korsawe, heavily based on voxelise from Adam A.
49 | % E-mail: johannes.korsawe@volkswagen.de
50 | % Release: 1.3
51 | % Release date: 25/09/2013
52 |
53 | % check number of inputs
54 | if nargin<3,
55 | fprintf('??? Error using ==> intriangulation\nThree input matrices are needed.\n');in=[];return;
56 | end
57 | if nargin==3,
58 | heavytest = 0;
59 | end
60 | % check size of inputs
61 | if size(vertices,2)~=3 || size(faces,2)~=3 || size(testp,2)~=3,
62 | fprintf('??? Error using ==> intriagulation\nAll input matrices must have three columns.\n');in=[];return;
63 | end
64 | ipmax = max(faces(:));zerofound = ~isempty(find(faces(:)==0, 1));
65 | if ipmax>size(vertices,1) || zerofound,
66 | fprintf('??? Error using ==> intriangulation\nThe triangulation data is defect. use trisurf(faces,vertices(:,1),vertices(:,2),vertices(:,3)) for test of deficiency.\n');return;
67 | end
68 |
69 | % loop for heavytest
70 | inreturn = zeros(size(testp,1),1);VER = vertices;TESTP = testp;
71 |
72 | for n = 1:heavytest+1,
73 |
74 | % Randomize
75 | if n>1,
76 | v=rand(1,3);D=rotmatrix(v/norm(v),rand*180/pi);vertices=VER*D;testp = TESTP*D;
77 | else,
78 | vertices=VER;
79 | end
80 |
81 | % Preprocessing data
82 | meshXYZ = zeros(size(faces,1),3,3);
83 | for loop = 1:3,
84 | meshXYZ(:,:,loop) = vertices(faces(:,loop),:);
85 | end
86 |
87 | % Basic idea (ingenious from FeX-submission voxelise):
88 | % If point is inside, it will cross the triangulation an uneven number of times in each direction (x, -x, y, -y, z, -z).
89 |
90 | % The function VOXELISEinternal is about 98% identical to its version inside voxelise.m.
91 | % This includes the elaborate comments. Thanks to Adam A!
92 |
93 | % z-direction:
94 | % intialization of results and correction list
95 | [in,cl] = VOXELISEinternal(testp(:,1),testp(:,2),testp(:,3),meshXYZ);
96 |
97 | % x-direction:
98 | % has only to be done for those points, that were not determinable in the first step --> cl
99 | [in2,cl2] = VOXELISEinternal(testp(cl,2),testp(cl,3),testp(cl,1),meshXYZ(:,[2,3,1],:));
100 | % Use results of x-direction that determined "inside"
101 | in(cl(in2==1)) = 1;
102 | % remaining indices with unclear result
103 | cl = cl(cl2);
104 |
105 | % y-direction:
106 | % has only to be done for those points, that were not determinable in the first and second step --> cl
107 | [in3,cl3] = VOXELISEinternal(testp(cl,3),testp(cl,1),testp(cl,2),meshXYZ(:,[3,1,2],:));
108 |
109 | % Use results of y-direction that determined "inside"
110 | in(cl(in3==1)) = 1;
111 | % remaining indices with unclear result
112 | cl = cl(cl3);
113 |
114 | % mark those indices, where all three tests have failed
115 | in(cl) = -1;
116 |
117 | if n==1,
118 | inreturn = in; % Starting guess
119 | else,
120 | % if ALWAYS inside, use as inside!
121 | % I = find(inreturn ~= in);
122 | % inreturn(I(in(I)==0)) = 0;
123 |
124 | % if AT LEAST ONCE inside, use as inside!
125 | I = find(inreturn ~= in);
126 | inreturn(I(in(I)==1)) = 1;
127 |
128 | end
129 |
130 | end
131 |
132 | in = inreturn;
133 |
134 | end
135 |
136 | %==========================================================================
137 | function [OUTPUT,correctionLIST] = VOXELISEinternal(testx,testy,testz,meshXYZ)
138 |
139 | % Prepare logical array to hold the logical data:
140 | OUTPUT = false(size(testx,1),1);
141 |
142 | %Identify the min and max x,y coordinates of the mesh:
143 | meshZmin = min(min(meshXYZ(:,3,:)));meshZmax = max(max(meshXYZ(:,3,:)));
144 |
145 | %Identify the min and max x,y,z coordinates of each facet:
146 | meshXYZmin = min(meshXYZ,[],3);meshXYZmax = max(meshXYZ,[],3);
147 |
148 | %======================================================
149 | % TURN OFF DIVIDE-BY-ZERO WARNINGS
150 | %======================================================
151 | %This prevents the Y1predicted, Y2predicted, Y3predicted and YRpredicted
152 | %calculations creating divide-by-zero warnings. Suppressing these warnings
153 | %doesn't affect the code, because only the sign of the result is important.
154 | %That is, 'Inf' and '-Inf' results are ok.
155 | %The warning will be returned to its original state at the end of the code.
156 | warningrestorestate = warning('query', 'MATLAB:divideByZero');
157 | %warning off MATLAB:divideByZero
158 |
159 | %======================================================
160 | % START COMPUTATION
161 | %======================================================
162 |
163 | correctionLIST = []; %Prepare to record all rays that fail the voxelisation. This array is built on-the-fly, but since
164 | %it ought to be relatively small should not incur too much of a speed penalty.
165 |
166 | % Loop through each testpoint.
167 | % The testpoint-array will be tested by passing rays in the z-direction through
168 | % each x,y coordinate of the testpoints, and finding the locations where the rays cross the mesh.
169 | facetCROSSLIST = zeros(1,1e3); % uses countindex: nf
170 | nm = size(meshXYZmin,1);
171 | for loop = 1:length(OUTPUT),
172 |
173 | nf = 0;
174 | % % - 1a - Find which mesh facets could possibly be crossed by the ray:
175 | % possibleCROSSLISTy = find( meshXYZmin(:,2)<=testy(loop) & meshXYZmax(:,2)>=testy(loop) );
176 |
177 | % % - 1b - Find which mesh facets could possibly be crossed by the ray:
178 | % possibleCROSSLIST = possibleCROSSLISTy( meshXYZmin(possibleCROSSLISTy,1)<=testx(loop) & meshXYZmax(possibleCROSSLISTy,1)>=testx(loop) );
179 |
180 | % Do - 1a - and - 1b - faster
181 | possibleCROSSLISTy = find((testy(loop)-meshXYZmin(:,2)).*(meshXYZmax(:,2)-testy(loop))>0);
182 | possibleCROSSLISTx = (testx(loop)-meshXYZmin(possibleCROSSLISTy,1)).*(meshXYZmax(possibleCROSSLISTy,1)-testx(loop))>0;
183 | possibleCROSSLIST = possibleCROSSLISTy(possibleCROSSLISTx);
184 |
185 | if isempty(possibleCROSSLIST)==0 %Only continue the analysis if some nearby facets were actually identified
186 |
187 | % - 2 - For each facet, check if the ray really does cross the facet rather than just passing it close-by:
188 |
189 | % GENERAL METHOD:
190 | % 1. Take each edge of the facet in turn.
191 | % 2. Find the position of the opposing vertex to that edge.
192 | % 3. Find the position of the ray relative to that edge.
193 | % 4. Check if ray is on the same side of the edge as the opposing vertex.
194 | % 5. If this is true for all three edges, then the ray definitely passes through the facet.
195 | %
196 | % NOTES:
197 | % 1. If the ray crosses exactly on an edge, this is counted as crossing the facet.
198 | % 2. If a ray crosses exactly on a vertex, this is also taken into account.
199 |
200 | for loopCHECKFACET = possibleCROSSLIST'
201 |
202 | %Check if ray crosses the facet. This method is much (>>10 times) faster than using the built-in function 'inpolygon'.
203 | %Taking each edge of the facet in turn, check if the ray is on the same side as the opposing vertex. If so, let testVn=1
204 |
205 | Y1predicted = meshXYZ(loopCHECKFACET,2,2) - ((meshXYZ(loopCHECKFACET,2,2)-meshXYZ(loopCHECKFACET,2,3)) * (meshXYZ(loopCHECKFACET,1,2)-meshXYZ(loopCHECKFACET,1,1))/(meshXYZ(loopCHECKFACET,1,2)-meshXYZ(loopCHECKFACET,1,3)));
206 | YRpredicted = meshXYZ(loopCHECKFACET,2,2) - ((meshXYZ(loopCHECKFACET,2,2)-meshXYZ(loopCHECKFACET,2,3)) * (meshXYZ(loopCHECKFACET,1,2)-testx(loop))/(meshXYZ(loopCHECKFACET,1,2)-meshXYZ(loopCHECKFACET,1,3)));
207 |
208 | if (Y1predicted > meshXYZ(loopCHECKFACET,2,1) && YRpredicted > testy(loop)) || (Y1predicted < meshXYZ(loopCHECKFACET,2,1) && YRpredicted < testy(loop)) || (meshXYZ(loopCHECKFACET,2,2)-meshXYZ(loopCHECKFACET,2,3)) * (meshXYZ(loopCHECKFACET,1,2)-testx(loop)) == 0
209 | % testV1 = 1; %The ray is on the same side of the 2-3 edge as the 1st vertex.
210 | else
211 | % testV1 = 0; %The ray is on the opposite side of the 2-3 edge to the 1st vertex.
212 | % As the check is for ALL three checks to be true, we can continue here, if only one check fails
213 | continue;
214 | end %if
215 |
216 | Y2predicted = meshXYZ(loopCHECKFACET,2,3) - ((meshXYZ(loopCHECKFACET,2,3)-meshXYZ(loopCHECKFACET,2,1)) * (meshXYZ(loopCHECKFACET,1,3)-meshXYZ(loopCHECKFACET,1,2))/(meshXYZ(loopCHECKFACET,1,3)-meshXYZ(loopCHECKFACET,1,1)));
217 | YRpredicted = meshXYZ(loopCHECKFACET,2,3) - ((meshXYZ(loopCHECKFACET,2,3)-meshXYZ(loopCHECKFACET,2,1)) * (meshXYZ(loopCHECKFACET,1,3)-testx(loop))/(meshXYZ(loopCHECKFACET,1,3)-meshXYZ(loopCHECKFACET,1,1)));
218 | if (Y2predicted > meshXYZ(loopCHECKFACET,2,2) && YRpredicted > testy(loop)) || (Y2predicted < meshXYZ(loopCHECKFACET,2,2) && YRpredicted < testy(loop)) || (meshXYZ(loopCHECKFACET,2,3)-meshXYZ(loopCHECKFACET,2,1)) * (meshXYZ(loopCHECKFACET,1,3)-testx(loop)) == 0
219 | % testV2 = 1; %The ray is on the same side of the 3-1 edge as the 2nd vertex.
220 | else
221 | % testV2 = 0; %The ray is on the opposite side of the 3-1 edge to the 2nd vertex.
222 | % As the check is for ALL three checks to be true, we can continue here, if only one check fails
223 | continue;
224 | end %if
225 |
226 | Y3predicted = meshXYZ(loopCHECKFACET,2,1) - ((meshXYZ(loopCHECKFACET,2,1)-meshXYZ(loopCHECKFACET,2,2)) * (meshXYZ(loopCHECKFACET,1,1)-meshXYZ(loopCHECKFACET,1,3))/(meshXYZ(loopCHECKFACET,1,1)-meshXYZ(loopCHECKFACET,1,2)));
227 | YRpredicted = meshXYZ(loopCHECKFACET,2,1) - ((meshXYZ(loopCHECKFACET,2,1)-meshXYZ(loopCHECKFACET,2,2)) * (meshXYZ(loopCHECKFACET,1,1)-testx(loop))/(meshXYZ(loopCHECKFACET,1,1)-meshXYZ(loopCHECKFACET,1,2)));
228 | if (Y3predicted > meshXYZ(loopCHECKFACET,2,3) && YRpredicted > testy(loop)) || (Y3predicted < meshXYZ(loopCHECKFACET,2,3) && YRpredicted < testy(loop)) || (meshXYZ(loopCHECKFACET,2,1)-meshXYZ(loopCHECKFACET,2,2)) * (meshXYZ(loopCHECKFACET,1,1)-testx(loop)) == 0
229 | % testV3 = 1; %The ray is on the same side of the 1-2 edge as the 3rd vertex.
230 | else
231 | % testV3 = 0; %The ray is on the opposite side of the 1-2 edge to the 3rd vertex.
232 | % As the check is for ALL three checks to be true, we can continue here, if only one check fails
233 | continue;
234 | end %if
235 |
236 | nf=nf+1;facetCROSSLIST(nf)=loopCHECKFACET;
237 |
238 | end %for
239 |
240 | % Use only values ~=0
241 | facetCROSSLIST = facetCROSSLIST(1:nf);
242 |
243 | % - 3 - Find the z coordinate of the locations where the ray crosses each facet:
244 | gridCOzCROSS = zeros(1,nf);
245 | for loopFINDZ = facetCROSSLIST
246 |
247 | % METHOD:
248 | % 1. Define the equation describing the plane of the facet. For a
249 | % more detailed outline of the maths, see:
250 | % http://local.wasp.uwa.edu.au/~pbourke/geometry/planeeq/
251 | % Ax + By + Cz + D = 0
252 | % where A = y1 (z2 - z3) + y2 (z3 - z1) + y3 (z1 - z2)
253 | % B = z1 (x2 - x3) + z2 (x3 - x1) + z3 (x1 - x2)
254 | % C = x1 (y2 - y3) + x2 (y3 - y1) + x3 (y1 - y2)
255 | % D = - x1 (y2 z3 - y3 z2) - x2 (y3 z1 - y1 z3) - x3 (y1 z2 - y2 z1)
256 | % 2. For the x and y coordinates of the ray, solve these equations to find the z coordinate in this plane.
257 |
258 | planecoA = meshXYZ(loopFINDZ,2,1)*(meshXYZ(loopFINDZ,3,2)-meshXYZ(loopFINDZ,3,3)) + meshXYZ(loopFINDZ,2,2)*(meshXYZ(loopFINDZ,3,3)-meshXYZ(loopFINDZ,3,1)) + meshXYZ(loopFINDZ,2,3)*(meshXYZ(loopFINDZ,3,1)-meshXYZ(loopFINDZ,3,2));
259 | planecoB = meshXYZ(loopFINDZ,3,1)*(meshXYZ(loopFINDZ,1,2)-meshXYZ(loopFINDZ,1,3)) + meshXYZ(loopFINDZ,3,2)*(meshXYZ(loopFINDZ,1,3)-meshXYZ(loopFINDZ,1,1)) + meshXYZ(loopFINDZ,3,3)*(meshXYZ(loopFINDZ,1,1)-meshXYZ(loopFINDZ,1,2));
260 | planecoC = meshXYZ(loopFINDZ,1,1)*(meshXYZ(loopFINDZ,2,2)-meshXYZ(loopFINDZ,2,3)) + meshXYZ(loopFINDZ,1,2)*(meshXYZ(loopFINDZ,2,3)-meshXYZ(loopFINDZ,2,1)) + meshXYZ(loopFINDZ,1,3)*(meshXYZ(loopFINDZ,2,1)-meshXYZ(loopFINDZ,2,2));
261 | planecoD = - meshXYZ(loopFINDZ,1,1)*(meshXYZ(loopFINDZ,2,2)*meshXYZ(loopFINDZ,3,3)-meshXYZ(loopFINDZ,2,3)*meshXYZ(loopFINDZ,3,2)) - meshXYZ(loopFINDZ,1,2)*(meshXYZ(loopFINDZ,2,3)*meshXYZ(loopFINDZ,3,1)-meshXYZ(loopFINDZ,2,1)*meshXYZ(loopFINDZ,3,3)) - meshXYZ(loopFINDZ,1,3)*(meshXYZ(loopFINDZ,2,1)*meshXYZ(loopFINDZ,3,2)-meshXYZ(loopFINDZ,2,2)*meshXYZ(loopFINDZ,3,1));
262 |
263 | if abs(planecoC) < 1e-14
264 | planecoC=0;
265 | end
266 |
267 | gridCOzCROSS(facetCROSSLIST==loopFINDZ) = (- planecoD - planecoA*testx(loop) - planecoB*testy(loop)) / planecoC;
268 |
269 | end %for
270 |
271 | if isempty(gridCOzCROSS),continue;end
272 |
273 | %Remove values of gridCOzCROSS which are outside of the mesh limits (including a 1e-12 margin for error).
274 | gridCOzCROSS = gridCOzCROSS( gridCOzCROSS>=meshZmin-1e-12 & gridCOzCROSS<=meshZmax+1e-12 );
275 |
276 | %Round gridCOzCROSS to remove any rounding errors, and take only the unique values:
277 | gridCOzCROSS = round(gridCOzCROSS*1e10)/1e10;
278 |
279 | % Replacement of the call to unique (gridCOzCROSS = unique(gridCOzCROSS);) by the following line:
280 | tmp = sort(gridCOzCROSS);I=[0,tmp(2:end)-tmp(1:end-1)]~=0;gridCOzCROSS = [tmp(1),tmp(I)];
281 |
282 | % - 4 - Label as being inside the mesh all the voxels that the ray passes through after crossing one facet before crossing another facet:
283 |
284 | if rem(numel(gridCOzCROSS),2)==0 % Only rays which cross an even number of facets are voxelised
285 |
286 | for loopASSIGN = 1:(numel(gridCOzCROSS)/2)
287 | voxelsINSIDE = (testz(loop)>gridCOzCROSS(2*loopASSIGN-1) & testz(loop)0
321 |
322 | %If necessary, add a one-pixel border around the x and y edges of the
323 | %array. This prevents an error if the code tries to interpolate a ray at
324 | %the edge of the x,y grid.
325 | if min(correctionLIST(:,1))==1 || max(correctionLIST(:,1))==numel(gridCOx) || min(correctionLIST(:,2))==1 || max(correctionLIST(:,2))==numel(gridCOy)
326 | gridOUTPUT = [zeros(1,voxcountY+2,voxcountZ);zeros(voxcountX,1,voxcountZ),gridOUTPUT,zeros(voxcountX,1,voxcountZ);zeros(1,voxcountY+2,voxcountZ)];
327 | correctionLIST = correctionLIST + 1;
328 | end
329 |
330 | for loopC = 1:countCORRECTIONLIST
331 | voxelsforcorrection = squeeze( sum( [ gridOUTPUT(correctionLIST(loopC,1)-1,correctionLIST(loopC,2)-1,:) ,...
332 | gridOUTPUT(correctionLIST(loopC,1)-1,correctionLIST(loopC,2),:) ,...
333 | gridOUTPUT(correctionLIST(loopC,1)-1,correctionLIST(loopC,2)+1,:) ,...
334 | gridOUTPUT(correctionLIST(loopC,1),correctionLIST(loopC,2)-1,:) ,...
335 | gridOUTPUT(correctionLIST(loopC,1),correctionLIST(loopC,2)+1,:) ,...
336 | gridOUTPUT(correctionLIST(loopC,1)+1,correctionLIST(loopC,2)-1,:) ,...
337 | gridOUTPUT(correctionLIST(loopC,1)+1,correctionLIST(loopC,2),:) ,...
338 | gridOUTPUT(correctionLIST(loopC,1)+1,correctionLIST(loopC,2)+1,:) ,...
339 | ] ) );
340 | voxelsforcorrection = (voxelsforcorrection>=4);
341 | gridOUTPUT(correctionLIST(loopC,1),correctionLIST(loopC,2),voxelsforcorrection) = 1;
342 | end %for
343 |
344 | %Remove the one-pixel border surrounding the array, if this was added
345 | %previously.
346 | if size(gridOUTPUT,1)>numel(gridCOx) || size(gridOUTPUT,2)>numel(gridCOy)
347 | gridOUTPUT = gridOUTPUT(2:end-1,2:end-1,:);
348 | end
349 |
350 | end %if
351 |
352 | %disp([' Ray tracing result: ',num2str(countCORRECTIONLIST),' rays (',num2str(countCORRECTIONLIST/(voxcountX*voxcountY)*100,'%5.1f'),'% of all rays) exactly crossed a facet edge and had to be computed by interpolation.'])
353 |
354 | end %function
355 | %==========================================================================
356 |
357 | function D = rotmatrix(v,deg)
358 | % calculate the rotation matrix about v by deg degrees
359 |
360 | deg=deg/180*pi;
361 | if deg~=0,
362 | v=v/norm(v);
363 | v1=v(1);v2=v(2);v3=v(3);ca=cos(deg);sa=sin(deg);
364 | D=[ca+v1*v1*(1-ca),v1*v2*(1-ca)-v3*sa,v1*v3*(1-ca)+v2*sa;
365 | v2*v1*(1-ca)+v3*sa,ca+v2*v2*(1-ca),v2*v3*(1-ca)-v1*sa;
366 | v3*v1*(1-ca)-v2*sa,v3*v2*(1-ca)+v1*sa,ca+v3*v3*(1-ca)];
367 | else,
368 | D=eye(3,3);
369 | end
370 |
371 | end
372 |
--------------------------------------------------------------------------------
/lk_H8.m:
--------------------------------------------------------------------------------
1 | %% === GENERATE ELEMENT STIFFNESS MATRIX ===
2 | function [KE] = lk_H8(nu)
3 | A = [32 6 -8 6 -6 4 3 -6 -10 3 -3 -3 -4 -8;
4 | -48 0 0 -24 24 0 0 0 12 -12 0 12 12 12];
5 | k = 1/144*A'*[1; nu];
6 | K1 = [k(1) k(2) k(2) k(3) k(5) k(5);
7 | k(2) k(1) k(2) k(4) k(6) k(7);
8 | k(2) k(2) k(1) k(4) k(7) k(6);
9 | k(3) k(4) k(4) k(1) k(8) k(8);
10 | k(5) k(6) k(7) k(8) k(1) k(2);
11 | k(5) k(7) k(6) k(8) k(2) k(1)];
12 | K2 = [k(9) k(8) k(12) k(6) k(4) k(7);
13 | k(8) k(9) k(12) k(5) k(3) k(5);
14 | k(10) k(10) k(13) k(7) k(4) k(6);
15 | k(6) k(5) k(11) k(9) k(2) k(10);
16 | k(4) k(3) k(5) k(2) k(9) k(12)
17 | k(11) k(4) k(6) k(12) k(10) k(13)];
18 | K3 = [k(6) k(7) k(4) k(9) k(12) k(8);
19 | k(7) k(6) k(4) k(10) k(13) k(10);
20 | k(5) k(5) k(3) k(8) k(12) k(9);
21 | k(9) k(10) k(2) k(6) k(11) k(5);
22 | k(12) k(13) k(10) k(11) k(6) k(4);
23 | k(2) k(12) k(9) k(4) k(5) k(3)];
24 | K4 = [k(14) k(11) k(11) k(13) k(10) k(10);
25 | k(11) k(14) k(11) k(12) k(9) k(8);
26 | k(11) k(11) k(14) k(12) k(8) k(9);
27 | k(13) k(12) k(12) k(14) k(7) k(7);
28 | k(10) k(9) k(8) k(7) k(14) k(11);
29 | k(10) k(8) k(9) k(7) k(11) k(14)];
30 | K5 = [k(1) k(2) k(8) k(3) k(5) k(4);
31 | k(2) k(1) k(8) k(4) k(6) k(11);
32 | k(8) k(8) k(1) k(5) k(11) k(6);
33 | k(3) k(4) k(5) k(1) k(8) k(2);
34 | k(5) k(6) k(11) k(8) k(1) k(8);
35 | k(4) k(11) k(6) k(2) k(8) k(1)];
36 | K6 = [k(14) k(11) k(7) k(13) k(10) k(12);
37 | k(11) k(14) k(7) k(12) k(9) k(2);
38 | k(7) k(7) k(14) k(10) k(2) k(9);
39 | k(13) k(12) k(10) k(14) k(7) k(11);
40 | k(10) k(9) k(2) k(7) k(14) k(7);
41 | k(12) k(2) k(9) k(11) k(7) k(14)];
42 | KE = 1/((nu+1)*(1-2*nu))*...
43 | [ K1 K2 K3 K4;
44 | K2' K5 K6 K3';
45 | K3' K6 K5' K2';
46 | K4 K3 K2 K1'];
47 | end
--------------------------------------------------------------------------------
/smoothedge3D.m:
--------------------------------------------------------------------------------
1 | function [vxPhys,xg,ls,top,tol] = smoothedge3D(vxPhys,Hn,Hns,nelx,nely,nelz,nele,nnele,nodex,nodey,nodez,fnx,fny,fnz,beta,ngrid)
2 | xn = reshape((Hn*vxPhys(:)./Hns),nely+1,nelx+1,nelz+1);
3 | %% UPDATE POINT DESNIGY BY A HEAVISIDE SMOOTH FUNCTION/ HEAVISIDE STEP FUNCTION
4 | xg = interp3(nodex,nodey,nodez,xn,fnx,fny,fnz,'linear');
5 | l1 =0; l2 = 1;
6 | while (l2-l1) > 1.0e-5
7 | ls = (l1+l2)/2.0;
8 | %% Heaviside smooth function
9 | xgnew = max(0.001,(tanh(beta*ls)+tanh(beta*(xg-ls)))/(tanh(beta*ls)+tanh(beta*(1-ls))));
10 | if sum(sum(sum(xgnew)))/((ngrid*nelx+1)*(ngrid*nely+1)*(ngrid*nelz+1)) - sum(vxPhys(:))/(nele) > 0
11 | l1 = ls;
12 | else
13 | l2 = ls;
14 | end
15 | end
16 | %% CONVERTING TO ELEMENTS
17 | vxPhys(:) = 0;
18 | Terr = 0;
19 | Tm=[];
20 | for nk = 1:nelz
21 | for ni = 1:nelx
22 | for nj = 1:nely
23 | ne = (nk-1)*nelx*nely+(ni-1)*nely+nj;
24 | for nk1 = ngrid*(nk-1)+1:ngrid*nk+1
25 | for ni1 = ngrid*(ni-1)+1:ngrid*ni+1
26 | for nj1 = ngrid*(nj-1)+1:ngrid*nj+1
27 | Tm=[Tm;xgnew(nj1,ni1,nk1)];
28 | vxPhys(ne) = vxPhys(ne)+xgnew(nj1,ni1,nk1);
29 | end
30 | end
31 | end
32 | if min(Tm)>0.001 && max(Tm)<1
33 | Terr=Terr+1;
34 | end
35 | Tm=[];
36 | end
37 | end
38 | end
39 | vxPhys = vxPhys/((ngrid+1)^3);
40 |
41 | %% Topology Error
42 | tol = Terr/(nnele);
43 | top = xg-ls;
--------------------------------------------------------------------------------
/stlgen.m:
--------------------------------------------------------------------------------
1 | function stlgen(top,fnx,fny,fnz,dx,dy,dz,nm)
2 | %% check model name nm
3 | nm1 = split(nm,'.');
4 | if length(nm1) > 1
5 | nm = strcat(string(nm1{1}),'.stl');
6 | else
7 | nm = strcat(string(nm1),'.stl');
8 | end
9 | % Dimensions of initial phi
10 | st_max = max([dx dy dz]);
11 | phi = top; phi = flip(phi,1);
12 | gmax = max([max(fnx(:)) max(fny(:)) max(fnz(:))]);
13 | gx = (fnx/gmax)*st_max; gy = (fny/gmax)*st_max; gz = (fnz/gmax)*st_max;
14 |
15 | phi_stl = phi; % if positive/negative defines material (+/-phi).
16 | limit = 0.00001; % the sign of the limit should match the sign of phi.
17 | phi_stl(phi_stl<=limit) = -1;
18 | phi_stl(phi_stl>limit) = 1;
19 | phi_stl = smooth3(phi);
20 |
21 | [faces1, vertices1] = isosurface(gx, gy, gz, phi_stl, 0);
22 | [faces2, vertices2] = isocaps(gx, gy, gz, phi_stl, 0);
23 | faces = [faces1; length(vertices1(:,1)) + faces2];
24 | vertices = [vertices1; vertices2];
25 | triangles = triangulation(faces, vertices);
26 |
27 | normals = faceNormal(triangles);
28 | vertices=vertices'; faces=faces'; normals=normals';
29 | % Transform vertices into single precision.
30 | datav = single(vertices);
31 | % Put all vertices of the faces in a single 2D matrix (3 x m).
32 | datavxyz = datav(:,faces);
33 | % Transform data to [V1, V2, V3] for each face in a (3 x 3 x m/3) matrix.
34 | dataxyz = reshape(datavxyz,3,3,numel(datavxyz)/9);
35 | % Reshape normals from (3 x m) to (3 x 1 x m) matrix.
36 | normals = reshape(normals,3,1,numel(normals)/3);
37 | % Include normal vectors: [n, V1, V2, V3] in a (3 x 4 x m/3) matrix.
38 | datanxyz = [normals(:,:,:), dataxyz(:,:,:)];
39 | % Transform datanxyz to 16-bit unsigned integer.
40 | datanxyz = typecast(datanxyz(:), 'uint16');
41 | % Reshape data. Each column will contain the information of one face.
42 | data = reshape(datanxyz(:), 24, numel(datanxyz)/24);
43 | % The 25th is the attribute byte count.
44 | data(25,:) = 0;
45 |
46 | % Generating stl file in Binary mode
47 | fileID = fopen(nm, 'w'); % name of stl file can be changed.
48 | % Write a title up to 80 characters. (80 bytes)
49 | fprintf(fileID, '%-80s',...
50 | 'exported using phi2stl created by P. Vogiatzis (Advisor: S. Chen)');
51 | % Write the number of faces in 32-bit unsigned integer.
52 | fwrite(fileID, numel(data)/25, 'uint32');
53 | % Write data.
54 | fwrite(fileID, data, 'uint16');
55 | fclose(fileID);
56 | end
57 |
--------------------------------------------------------------------------------
/supportDOFs.m:
--------------------------------------------------------------------------------
1 | function fixeddof = supportDOFs(sup_all,sup_x,sup_y,sup_z)
2 |
3 | fn1 = sup_all; fixeddof1 = reshape([fn1*3-2 fn1*3-1 fn1*3]'...
4 | ,1,3*length(fn1)); %fixed dofs in all directions
5 |
6 | fn2 = sup_x; fixeddof2 = (fn2*3-2)'; %fixed dofs in x direction
7 |
8 | fn3 = sup_y; fixeddof3 = (fn3*3-1)'; %fixed dofs in y direction
9 |
10 | fn4 = sup_z; fixeddof4 = (fn4*3)'; %fixed dofs in z direction
11 |
12 | fixeddof = union(fixeddof1,union(fixeddof2,union(fixeddof3,fixeddof4)));
--------------------------------------------------------------------------------
/symmetry.m:
--------------------------------------------------------------------------------
1 | function [xg,top,fnx,fny,fnz,nelx,nely,nelz,dx,dy,dz] = symmetry(xg,ls,nelx,nely,nelz,dx,dy,dz,ngrid,symm,dir)
2 | if strcmp(symm,'x-y')
3 | if strcmp(dir,'left')
4 | [sx,sy,sz] = size(xg); xg1 = zeros(sx,sy,2*sz); xg_mir = flip(xg,3); xg1(:,:,1:sz) = xg_mir; xg1(:,:,sz+1:end) = xg;
5 | xg = xg1;
6 | nelz = 2*nelz; dz = 2*dz; [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx+5,0:1/ngrid:nely+5,0:1/ngrid:nelz+5);
7 | fnx(:,:,size(xg,3)+1:end) = []; fny(:,:,size(xg,3)+1:end) = []; fnz(:,:,size(xg,3)+1:end) = [];
8 | fnx(:,size(xg,2)+1:end,:) = []; fny(:,size(xg,2)+1:end,:) = []; fnz(:,size(xg,2)+1:end,:) = [];
9 | fnx(size(xg,1)+1:end,:,:) = []; fny(size(xg,1)+1:end,:,:) = []; fnz(size(xg,1)+1:end,:,:) = [];
10 | else
11 | [sx,sy,sz] = size(xg); xg1 = zeros(sx,sy,2*sz); xg_mir = flip(xg,3); xg1(:,:,1:sz) = xg; xg1(:,:,sz+1:end) = xg_mir;
12 | xg = xg1;
13 | nelz = 2*nelz; dz = 2*dz; [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx+5,0:1/ngrid:nely+5,0:1/ngrid:nelz+5);
14 | fnx(:,:,size(xg,3)+1:end) = []; fny(:,:,size(xg,3)+1:end) = []; fnz(:,:,size(xg,3)+1:end) = [];
15 | fnx(:,size(xg,2)+1:end,:) = []; fny(:,size(xg,2)+1:end,:) = []; fnz(:,size(xg,2)+1:end,:) = [];
16 | fnx(size(xg,1)+1:end,:,:) = []; fny(size(xg,1)+1:end,:,:) = []; fnz(size(xg,1)+1:end,:,:) = [];
17 | end
18 | elseif strcmp(symm,'y-z')
19 | if strcmp(dir,'left')
20 | [sx,sy,sz] = size(xg); xg1 = zeros(sx,2*sy,sz); xg_mir = flip(xg,2); xg1(:,1:sy,:) = xg_mir; xg1(:,sy+1:end,:) = xg;
21 | xg = xg1;
22 | nelx = 2*nelx; dx = 2*dx; [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx+5,0:1/ngrid:nely+5,0:1/ngrid:nelz+5);
23 | fnx(:,:,size(xg,3)+1:end) = []; fny(:,:,size(xg,3)+1:end) = []; fnz(:,:,size(xg,3)+1:end) = [];
24 | fnx(:,size(xg,2)+1:end,:) = []; fny(:,size(xg,2)+1:end,:) = []; fnz(:,size(xg,2)+1:end,:) = [];
25 | fnx(size(xg,1)+1:end,:,:) = []; fny(size(xg,1)+1:end,:,:) = []; fnz(size(xg,1)+1:end,:,:) = [];
26 | else
27 | [sx,sy,sz] = size(xg); xg1 = zeros(sx,2*sy,sz); xg_mir = flip(xg,2); xg1(:,1:sy,:) = xg; xg1(:,sy+1:end,:) = xg_mir;
28 | xg = xg1;
29 | nelx = 2*nelx; dx = 2*dx; [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx+5,0:1/ngrid:nely+5,0:1/ngrid:nelz+5);
30 | fnx(:,:,size(xg,3)+1:end) = []; fny(:,:,size(xg,3)+1:end) = []; fnz(:,:,size(xg,3)+1:end) = [];
31 | fnx(:,size(xg,2)+1:end,:) = []; fny(:,size(xg,2)+1:end,:) = []; fnz(:,size(xg,2)+1:end,:) = [];
32 | fnx(size(xg,1)+1:end,:,:) = []; fny(size(xg,1)+1:end,:,:) = []; fnz(size(xg,1)+1:end,:,:) = [];
33 | end
34 | elseif strcmp(symm,'z-x')
35 | if strcmp(dir,'right')
36 | [sx,sy,sz] = size(xg); xg1 = zeros(2*sx,sy,sz); xg_mir = flip(xg,1); xg1(1:sx,:,:) = xg; xg1(sx+1:end,:,:) = xg_mir;
37 | xg = xg1;
38 | nely = 2*nely; dy = 2*dy; [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx+5,0:1/ngrid:nely+5,0:1/ngrid:nelz+5);
39 | fnx(:,:,size(xg,3)+1:end) = []; fny(:,:,size(xg,3)+1:end) = []; fnz(:,:,size(xg,3)+1:end) = [];
40 | fnx(:,size(xg,2)+1:end,:) = []; fny(:,size(xg,2)+1:end,:) = []; fnz(:,size(xg,2)+1:end,:) = [];
41 | fnx(size(xg,1)+1:end,:,:) = []; fny(size(xg,1)+1:end,:,:) = []; fnz(size(xg,1)+1:end,:,:) = [];
42 | else
43 | [sx,sy,sz] = size(xg); xg1 = zeros(2*sx,sy,sz); xg_mir = flip(xg,1); xg1(1:sx,:,:) = xg_mir; xg1(sx+1:end,:,:) = xg;
44 | xg = xg1;
45 | nely = 2*nely; dy = 2*dy; [fnx,fny,fnz] = meshgrid(0:1/ngrid:nelx+5,0:1/ngrid:nely+5,0:1/ngrid:nelz+5);
46 | fnx(:,:,size(xg,3)+1:end) = []; fny(:,:,size(xg,3)+1:end) = []; fnz(:,:,size(xg,3)+1:end) = [];
47 | fnx(:,size(xg,2)+1:end,:) = []; fny(:,size(xg,2)+1:end,:) = []; fnz(:,size(xg,2)+1:end,:) = [];
48 | fnx(size(xg,1)+1:end,:,:) = []; fny(size(xg,1)+1:end,:,:) = []; fnz(size(xg,1)+1:end,:,:) = [];
49 | end
50 | end
51 | top = xg-ls;
--------------------------------------------------------------------------------