Disabled external gits
This commit is contained in:
5316 files changed
+4563444
-6
No files matched your search
@@ -0,0 +1,834 @@
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 0.5
|
||||
v 3.06161699786838e-17 -7.49879891330929e-33 -0.5
|
||||
v 0.154508497187474 -3.78436673043416e-17 -0.475528258147577
|
||||
v 0.293892626146237 -7.19829327805997e-17 -0.404508497187474
|
||||
v 0.404508497187474 -9.90760072617093e-17 -0.293892626146236
|
||||
v 0.475528258147577 -1.16470831848909e-16 -0.154508497187473
|
||||
v 0.5 -1.22464679914735e-16 7.6571373978539e-16
|
||||
v 0.475528258147577 -1.16470831848909e-16 0.154508497187474
|
||||
v 0.404508497187474 -9.90760072617092e-17 0.293892626146237
|
||||
v 0.293892626146237 -7.19829327805998e-17 0.404508497187473
|
||||
v 0.154508497187475 -3.78436673043417e-17 0.475528258147576
|
||||
v 0.21857645514496 0.136716465258129 0.428407447861946
|
||||
v 0.475945187701446 -0.132880263668928 0.0762824608354488
|
||||
v 0.218576349120797 -0.134908613951094 -0.428980239040003
|
||||
v 0.228603425820446 -0.140038091834834 0.422054269660211
|
||||
v 0.437104447096958 0.151793486569612 0.189468835862535
|
||||
v 0.42898023903994 0.134908613950884 -0.21857634912105
|
||||
v 0.428980239039898 -0.134908613951062 -0.218576349121023
|
||||
v 0.218576349121032 0.134908613951053 -0.428980239039896
|
||||
v 0.340440645253916 0.134908613951044 0.34044064525392
|
||||
v 0.476615030125843 -0.131924241455095 -0.0737163996315581
|
||||
v 0.407622547196207 -0.259520994885 -0.128423955051913
|
||||
v 0.338436818269637 -0.252043139096244 -0.26820659215246
|
||||
v 0.340989631871085 -0.116746524471516 -0.34654915954341
|
||||
v 0.075316277025205 -0.134908613951047 0.475528258147578
|
||||
v 0.0753162770252058 0.134908613951052 -0.475528258147577
|
||||
v 0.337051887252752 0.13152434625125 -0.345104870499591
|
||||
v 0.342307229899869 0.259749321291958 -0.255648294433281
|
||||
v 0.235302886190634 0.257758938760451 0.358040334654413
|
||||
v 0.0930553185121102 0.241091096498632 0.428037137273972
|
||||
v 0.414887348894352 0.253233345682864 -0.117223548665273
|
||||
v 0.309219636002729 0.365205559163796 -0.144941768535501
|
||||
v 0.116382730487621 0.357335962703667 0.329797013029059
|
||||
v 0.220295554503833 0.356044147287606 -0.273317459830304
|
||||
v 0.173924737961772 0.443407381211481 -0.152118637293744
|
||||
v 0.0757439138278267 0.415836842579461 -0.2671003179923
|
||||
v 0.0224933467184133 0.480041055177656 -0.138038526134294
|
||||
v 0.248065266401332 0.358015947011543 0.245536566096914
|
||||
v 0.138163331821839 0.43047956133561 0.21353744639334
|
||||
v 0.360552014587397 0.346405942121308 -0.00227333235984791
|
||||
v 0.123093945281709 0.484207258358844 -0.0197790694319915
|
||||
v -0.0375624502146155 0.498585389330104 0.0012930121510933
|
||||
v -0.0319756224028659 0.329253812136088 0.374925975048146
|
||||
v -0.0571707300985015 0.188277472409031 0.459655415505214
|
||||
v 0.44634465869394 0.222444950782125 0.0359817943817138
|
||||
v 0.114071738612042 0.30750614917439 -0.377395822274126
|
||||
v 0.236387555749274 0.430565411758525 0.0934577427723124
|
||||
v 0.378115930351658 0.292151103254715 0.147227973161872
|
||||
v 0.0698331513994325 -0.131524346251195 -0.477309833660296
|
||||
v -0.0276507157238025 0.368077837732622 -0.337274581446689
|
||||
v -0.132019323454869 0.46789161623721 -0.116826083086996
|
||||
v -0.178527337205295 0.268217150323689 0.382344805303572
|
||||
v -0.195982573985885 0.117715178528912 0.444672876885665
|
||||
v -0.188769871137012 0.462097824846099 0.0288363663352296
|
||||
v -0.311118332326446 0.185953595932789 0.344422187801651
|
||||
v 0.298513275017753 -0.364576673892107 -0.167253321318123
|
||||
v -0.27446477920923 0.408828269442573 -0.0867671082739308
|
||||
v -0.321076581736832 0.0337877006396921 0.381796044958135
|
||||
v -0.406068994209582 0.0890512487956863 0.27780901178606
|
||||
v -0.396337226815336 -0.0658166787739775 0.297632268807486
|
||||
v 0.137344602759695 -0.267387515925555 0.399550217644719
|
||||
v -0.469353412437567 -0.00745235730436951 0.172197086513736
|
||||
v -0.438850244007533 -0.16046355744979 0.17793793880195
|
||||
v -0.488260481987745 -0.0978280168539874 0.0450708425427184
|
||||
v -0.433483128474169 -0.244453321072111 0.0483213321946162
|
||||
v -0.460620100758965 -0.173287974513347 -0.0883198769579221
|
||||
v -0.383511806626786 -0.309356779000242 -0.08495338406711
|
||||
v -0.336717499334961 -0.365993326701377 0.0516740791080927
|
||||
v -0.267862281691792 -0.414575366652434 -0.0798565176542698
|
||||
v -0.205085219904653 -0.452251021719178 0.0583872069088724
|
||||
v -0.389473197418456 -0.226083984285031 -0.217247924138414
|
||||
v -0.445256364809781 -0.0799966822341631 -0.212949055945092
|
||||
v -0.00351125947165275 -0.267035886479874 0.422704987418922
|
||||
v -0.353169743739217 -0.125114465368412 -0.331085340452809
|
||||
v -0.38892388844103 0.0261181792321889 -0.313139026174485
|
||||
v -0.278756909608118 -0.262391732725563 -0.321628922740179
|
||||
v -0.249429844449192 -0.39750217428021 0.172559480007787
|
||||
v -0.125203314206269 -0.478452051724907 -0.0735375027587528
|
||||
v -0.0528582364531956 -0.493487744300911 0.0606288138087549
|
||||
v 0.271731582933658 -0.249600298700644 0.337433901267964
|
||||
v -0.495847117939593 0.0542719818547096 0.034499095880349
|
||||
v 0.341636271151409 -0.364235836672196 -0.0248377438078891
|
||||
v -0.278221380393658 -0.0165162196036634 -0.415114535979952
|
||||
v -0.385894465893779 0.231366911979078 0.218070661102819
|
||||
v 0.129422773211733 -0.26368230955868 -0.404624993543385
|
||||
v 0.17079787798835 -0.360453290963367 0.301498772648173
|
||||
v -0.2972397651044 0.134475553784439 -0.378899521608367
|
||||
v -0.390729424978202 0.17308135749756 -0.259563788196669
|
||||
v 0.0302401087170613 -0.494617483324727 -0.0666264287973931
|
||||
v -0.0447104151313644 -0.455911463185833 -0.200363960118914
|
||||
v -0.289781305004565 -0.107480642258869 0.393032704503674
|
||||
v -0.28072748874216 0.276043192337753 -0.308208100199367
|
||||
v 0.106085899784673 -0.483055958177403 0.0735032185430484
|
||||
v -0.143288452953271 0.380504725979635 0.291006138693707
|
||||
v -0.0207720062787277 -0.262149359393134 -0.425260199319106
|
||||
v -0.0793282266177742 -0.112493174960849 0.480679017691543
|
||||
v -0.210229488803243 0.104747954203238 -0.441397131988602
|
||||
v 0.435024352571936 -0.127806035969131 0.210759174982314
|
||||
v 0.298839864283654 -0.34288662805342 0.207661974894498
|
||||
v -0.343961566185834 -0.213169748618088 0.293681969588004
|
||||
v -0.217656630917657 -0.259665634918282 0.367694641054313
|
||||
v -0.318981501523703 0.381763369474201 0.0500752574969736
|
||||
v -0.395445063483211 0.303503289973959 -0.0388452666581461
|
||||
v 0.00695685172784659 -0.466794760772503 0.179037017204205
|
||||
v -0.141786434074944 -0.0639250457860653 -0.475194902785753
|
||||
v 0.123376202006679 -0.445805073774975 -0.189831896621448
|
||||
v 0.0273264572598231 -0.36207385125428 -0.343737968475292
|
||||
v -0.179178868825853 0.231344360320625 -0.40543152308883
|
||||
v -0.131442519100517 -0.37228536331636 -0.30680037880178
|
||||
v 0.213344976802497 -0.44944368426887 -0.0498427080320272
|
||||
v -0.095411435088729 0.468568967697982 0.146081417588813
|
||||
v 0.19556911033449 -0.349389679263868 -0.299465482329545
|
||||
v -0.212579734450761 0.392914303643436 -0.22456225527287
|
||||
v 0.00442729082563762 0.431790532829453 0.252066131907487
|
||||
v 0.251435921428911 -0.424020659066107 0.0835850351458869
|
||||
v -0.0716881267417996 0.0362403081699758 0.493505271043782
|
||||
v 0.409702957808806 -0.250532734704164 0.139200701163351
|
||||
v 0.354048851093961 -0.123591021755264 0.33071841554491
|
||||
v -0.409329654955812 0.269763307055223 0.0983717019288848
|
||||
v -0.23775056881332 0.409432492346691 0.160747321096556
|
||||
v -0.280167779637764 0.310303261210272 0.274258821799984
|
||||
v 0.0390199999029228 -0.340176969429353 0.364358434892671
|
||||
v -0.106955495739533 -0.389774683020182 0.294340310538035
|
||||
v -0.125152025350624 -0.457070129870627 0.159448634144933
|
||||
v 0.250205349609497 0.430527105380925 -0.0452072401182732
|
||||
v -0.15862733630032 -0.0449406159687499 0.472035707563119
|
||||
v -0.372118237460504 -0.283526014116421 0.176468174662014
|
||||
v -0.235245742246689 -0.152187819676347 -0.41412354231191
|
||||
v 0.479986141812706 0.124680814448665 -0.063780860578784
|
||||
v -0.0761042573074939 0.431963531953512 -0.240032600039915
|
||||
v -0.288453021308633 -0.353652776154199 -0.204265925734934
|
||||
v -0.458840137015611 0.057463941494015 -0.190167358112447
|
||||
v -0.444083105517519 0.194920415588484 -0.121639742603844
|
||||
v -0.178055249060845 -0.43316536366806 -0.175111667230364
|
||||
v -0.491963173165518 -0.0298523928793253 -0.0841490991531884
|
||||
v -0.45636138284715 0.138396610027018 0.150268648023688
|
||||
v -0.345904715972311 0.313415014736247 -0.179223201639723
|
||||
v -0.153169726530236 -0.269052072762942 -0.392619430258638
|
||||
v -0.0419923946510265 0.170189522618945 -0.468265058681734
|
||||
v 0.243612070418092 0.241981955824921 -0.363452737232445
|
||||
v 0.338867576345089 0.252678472264692 0.2670624559087
|
||||
v 0.426863022631355 -0.25994025908482 0.0147993789376581
|
||||
v 0.158342102182598 -0.434609327079221 0.18984865417522
|
||||
v 0.0452931243905481 0.0952764475019849 0.488744239285072
|
||||
v -0.237259629761916 0.0166159415076913 0.439808797744033
|
||||
v 0.247175666187241 -0.238473344419651 -0.363365730423495
|
||||
v 0.0577997827759178 0.48434516267528 0.10985876616872
|
||||
v -0.334770924239934 0.332574086299653 0.165296416795679
|
||||
v -0.153183582101622 0.339412359720881 -0.333667559470828
|
||||
v 0.36785960116632 -0.228792320684729 0.249666553277471
|
||||
v 0.483390586525237 0.102332156736947 0.0765615475049495
|
||||
v 0.139648641361451 0.213951152339616 -0.429794324507027
|
||||
v -0.0358864034291634 0.302032201639968 -0.396848478920397
|
||||
v -0.180786711862885 -0.175443810495746 0.431897712627121
|
||||
v 0.348215026659532 -0.346723777603642 0.0923521372398145
|
||||
v -0.114480413553308 -0.290654614949134 0.390402522688358
|
||||
v -0.272442803422386 -0.321472772094441 0.269128548588341
|
||||
v -0.466114498296331 0.180818120755528 0.00648703972541844
|
||||
v -0.129415184584831 -0.203585571998795 -0.437955048918034
|
||||
v 0.0643376427947934 -0.412575814735467 0.275030661590622
|
||||
v -0.485934856252322 0.0906364933467189 -0.0751820560562512
|
||||
v -2.77555756156289e-16 3.19189119579733e-16 -1.2490009027033e-16
|
||||
v -0.251828742757562 0.0139490906784806 -0.0181338406388946
|
||||
v 0.197996662720562 -0.0791211777945037 0.136432807235424
|
||||
v 0.125255777218953 0.210831018463626 -0.063969097850248
|
||||
v -0.139628236563409 -0.21265335644906 0.00545121255949739
|
||||
v -0.145223690886062 0.189924594351579 0.11159305462841
|
||||
v -0.112897563504534 -0.0373976158431084 -0.223966661594476
|
||||
v 0.225528258147577 -0.0232431701377701 -0.114912387106339
|
||||
v -0.118530098445147 -0.0689806932344922 0.2117841676383
|
||||
v 0.098269738040353 0.147959392484917 0.178021817259433
|
||||
v 0.100852235573853 -0.219450649709681 -0.0387973024559412
|
||||
v -0.100480207820675 0.192284757140571 -0.148991345058649
|
||||
v 0.08807336311451 0.0516996280513727 -0.271061939721184
|
||||
v 0.272113071694785 0.101244013250397 0.0512575837900759
|
||||
v 0.0341720627218518 -0.221571915156144 0.170600381517002
|
||||
v 0.113793744063312 -0.150466918879953 -0.232830800332848
|
||||
v 0.068592399702004 -0.0245878691620408 0.288679790541826
|
||||
v -0.0741210186337665 0.111594614690448 0.278407708187608
|
||||
v -0.0351094203418499 0.30351870487887 -0.00261521319733849
|
||||
v -0.258447343925187 0.0495111872633636 0.167086499211952
|
||||
v -0.271439309774019 -0.125349807194904 0.104052998028547
|
||||
v -0.0485204373172835 -0.250891695571267 -0.169649174254392
|
||||
v -0.245408905954284 -0.137064807392418 -0.132337064396614
|
||||
v -0.247561324014027 0.19563057757812 -0.0400712992459122
|
||||
v -0.245489451032576 0.0855397985783712 -0.187709278356085
|
||||
v 0.27254656245515 -0.16399276001755 -0.00766125806031415
|
||||
v 0.273716986928946 0.149504817170547 -0.136480234333616
|
||||
v 0.0525334922800396 0.245214764318482 -0.222591039627852
|
||||
v -0.025453222260026 0.265072731295802 0.212780231418037
|
||||
v 0.10188342337719 0.303246953287615 0.102540160700209
|
||||
v -0.14157478784597 -0.241776139413833 0.180194715613577
|
||||
v -0.0121617817639016 -0.325829668630181 0.0394634260162139
|
||||
v 0.222619980200421 0.0438990087026778 0.254181668630204
|
||||
v 0.187862004819913 -0.26556009247797 0.101876795667186
|
||||
v 0.342239361396159 -0.0424148965243595 0.0738730045314498
|
||||
v -0.120466338945889 0.114580505991094 -0.297963959751455
|
||||
v 0.15154406307463 -0.163641254596307 0.268108582070898
|
||||
f 166 170 163 182
|
||||
f 165 162 171 180
|
||||
f 167 171 162 180
|
||||
f 4 5 27 169
|
||||
f 163 166 162 170
|
||||
f 4 24 169 177
|
||||
f 167 173 163 185
|
||||
f 162 163 167 173
|
||||
f 158 136 181 185
|
||||
f 162 171 170 178
|
||||
f 162 163 170 181
|
||||
f 162 167 163 181
|
||||
f 4 169 27 174
|
||||
f 170 171 162 179
|
||||
f 162 173 165 174
|
||||
f 170 178 171 179
|
||||
f 158 181 163 185
|
||||
f 162 176 164 178
|
||||
f 162 170 167 181
|
||||
f 162 170 176 178
|
||||
f 162 166 163 184
|
||||
f 167 170 162 179
|
||||
f 129 169 6 196
|
||||
f 162 165 169 174
|
||||
f 73 176 170 178
|
||||
f 119 181 136 185
|
||||
f 4 169 174 177
|
||||
f 72 132 135 163
|
||||
f 27 174 169 188
|
||||
f 158 119 136 185
|
||||
f 64 66 163 182
|
||||
f 167 162 171 179
|
||||
f 66 135 64 163
|
||||
f 7 129 6 196
|
||||
f 162 173 167 180
|
||||
f 95 177 168 183
|
||||
f 162 177 172 183
|
||||
f 4 24 5 169
|
||||
f 27 169 5 188
|
||||
f 162 169 165 175
|
||||
f 162 164 169 175
|
||||
f 129 175 169 196
|
||||
f 168 177 162 183
|
||||
f 132 161 135 163
|
||||
f 119 148 84 167
|
||||
f 162 165 173 180
|
||||
f 164 162 171 175
|
||||
f 165 171 162 175
|
||||
f 158 81 161 163
|
||||
f 30 171 178 179
|
||||
f 64 81 62 163
|
||||
f 169 162 174 177
|
||||
f 66 163 182 184
|
||||
f 169 177 23 187
|
||||
f 162 170 166 176
|
||||
f 54 167 102 185
|
||||
f 68 166 67 182
|
||||
f 162 168 163 173
|
||||
f 164 171 162 178
|
||||
f 161 158 163 185
|
||||
f 65 68 67 182
|
||||
f 166 168 162 183
|
||||
f 129 6 169 188
|
||||
f 162 163 168 184
|
||||
f 165 175 40 191
|
||||
f 129 169 175 188
|
||||
f 119 167 84 181
|
||||
f 62 64 163 182
|
||||
f 18 169 23 187
|
||||
f 67 182 166 184
|
||||
f 162 168 166 184
|
||||
f 168 174 162 177
|
||||
f 164 162 169 172
|
||||
f 167 181 119 185
|
||||
f 126 178 170 179
|
||||
f 72 163 135 184
|
||||
f 72 132 163 186
|
||||
f 54 180 167 185
|
||||
f 62 163 81 181
|
||||
f 162 168 173 174
|
||||
f 66 135 163 184
|
||||
f 165 174 173 189
|
||||
f 38 141 171 191
|
||||
f 140 174 188 189
|
||||
f 161 163 132 186
|
||||
f 24 23 18 169
|
||||
f 62 163 181 182
|
||||
f 65 182 67 184
|
||||
f 166 162 172 183
|
||||
f 140 174 27 188
|
||||
f 162 166 172 176
|
||||
f 4 14 24 177
|
||||
f 23 169 24 177
|
||||
f 169 172 162 177
|
||||
f 163 173 168 186
|
||||
f 60 181 170 182
|
||||
f 119 148 167 185
|
||||
f 57 173 51 180
|
||||
f 72 163 184 186
|
||||
f 41 35 165 180
|
||||
f 41 37 35 180
|
||||
f 141 171 48 175
|
||||
f 56 177 172 187
|
||||
f 135 161 81 163
|
||||
f 95 49 168 177
|
||||
f 102 54 120 167
|
||||
f 34 140 188 189
|
||||
f 176 178 73 198
|
||||
f 162 172 164 176
|
||||
f 141 171 175 194
|
||||
f 60 170 91 182
|
||||
f 130 37 180 189
|
||||
f 56 23 177 187
|
||||
f 22 18 23 187
|
||||
f 121 55 167 179
|
||||
f 6 169 21 196
|
||||
f 60 91 100 182
|
||||
f 12 30 171 178
|
||||
f 65 66 182 184
|
||||
f 91 170 100 182
|
||||
f 164 172 169 187
|
||||
f 116 178 126 179
|
||||
f 125 165 40 191
|
||||
f 69 67 166 184
|
||||
f 96 73 170 178
|
||||
f 113 51 57 173
|
||||
f 57 173 180 185
|
||||
f 136 119 84 181
|
||||
f 84 167 121 181
|
||||
f 83 75 74 186
|
||||
f 134 131 69 183
|
||||
f 167 179 55 181
|
||||
f 130 180 173 189
|
||||
f 145 179 170 181
|
||||
f 48 171 141 191
|
||||
f 48 175 171 191
|
||||
f 102 167 148 185
|
||||
f 64 135 81 163
|
||||
f 30 178 144 179
|
||||
f 57 180 54 185
|
||||
f 121 52 55 179
|
||||
f 40 175 165 188
|
||||
f 60 91 170 181
|
||||
f 130 51 173 180
|
||||
f 76 183 168 184
|
||||
f 74 75 72 184
|
||||
f 140 19 27 174
|
||||
f 165 180 171 191
|
||||
f 49 174 168 177
|
||||
f 83 74 168 186
|
||||
f 84 121 55 181
|
||||
f 69 70 78 166
|
||||
f 120 167 54 180
|
||||
f 121 167 55 181
|
||||
f 148 121 84 167
|
||||
f 74 128 168 184
|
||||
f 131 166 69 183
|
||||
f 156 170 176 192
|
||||
f 74 75 184 186
|
||||
f 67 68 69 166
|
||||
f 65 67 66 184
|
||||
f 117 164 150 196
|
||||
f 96 156 154 170
|
||||
f 98 150 164 196
|
||||
f 145 170 58 181
|
||||
f 161 133 158 185
|
||||
f 24 18 5 169
|
||||
f 78 183 166 193
|
||||
f 34 32 165 188
|
||||
f 98 117 150 196
|
||||
f 41 35 125 165
|
||||
f 35 34 32 165
|
||||
f 73 156 170 176
|
||||
f 74 184 168 186
|
||||
f 72 184 75 186
|
||||
f 133 161 132 186
|
||||
f 119 102 148 185
|
||||
f 150 164 117 195
|
||||
f 34 188 165 189
|
||||
f 57 54 102 185
|
||||
f 148 102 120 167
|
||||
f 170 181 163 182
|
||||
f 12 178 171 194
|
||||
f 6 18 21 169
|
||||
f 5 169 6 188
|
||||
f 136 62 81 181
|
||||
f 171 180 167 190
|
||||
f 58 170 91 181
|
||||
f 78 166 70 193
|
||||
f 2 168 49 174
|
||||
f 34 140 28 188
|
||||
f 40 125 32 165
|
||||
f 38 48 141 191
|
||||
f 169 174 165 188
|
||||
f 40 175 48 191
|
||||
f 113 130 51 173
|
||||
f 66 72 135 184
|
||||
f 169 187 21 196
|
||||
f 131 166 183 184
|
||||
f 74 128 83 168
|
||||
f 18 21 169 187
|
||||
f 7 6 21 196
|
||||
f 64 65 66 182
|
||||
f 69 166 131 184
|
||||
f 56 112 172 177
|
||||
f 76 168 128 184
|
||||
f 166 182 68 192
|
||||
f 159 95 168 183
|
||||
f 34 165 35 189
|
||||
f 96 170 126 178
|
||||
f 172 183 89 193
|
||||
f 150 118 98 164
|
||||
f 172 177 106 183
|
||||
f 168 183 166 184
|
||||
f 111 167 120 180
|
||||
f 17 5 6 188
|
||||
f 30 171 179 190
|
||||
f 130 37 51 180
|
||||
f 40 165 32 188
|
||||
f 100 182 170 192
|
||||
f 112 106 172 177
|
||||
f 74 76 128 184
|
||||
f 170 179 167 181
|
||||
f 32 125 35 165
|
||||
f 41 165 125 191
|
||||
f 113 173 57 185
|
||||
f 2 168 174 197
|
||||
f 18 6 5 169
|
||||
f 167 180 111 190
|
||||
f 126 170 145 179
|
||||
f 12 144 30 178
|
||||
f 91 126 154 170
|
||||
f 69 68 70 166
|
||||
f 4 27 19 174
|
||||
f 137 92 173 186
|
||||
f 25 73 178 198
|
||||
f 29 171 141 194
|
||||
f 60 58 91 181
|
||||
f 120 167 111 190
|
||||
f 111 120 54 180
|
||||
f 150 118 164 198
|
||||
f 30 33 29 171
|
||||
f 69 131 67 184
|
||||
f 95 49 159 168
|
||||
f 68 182 127 192
|
||||
f 117 187 164 196
|
||||
f 166 176 170 192
|
||||
f 33 171 30 190
|
||||
f 57 51 54 180
|
||||
f 137 92 113 173
|
||||
f 22 23 56 187
|
||||
f 37 36 35 189
|
||||
f 29 38 141 171
|
||||
f 150 164 195 198
|
||||
f 180 190 171 191
|
||||
f 145 91 58 170
|
||||
f 41 180 165 191
|
||||
f 82 187 172 195
|
||||
f 137 173 185 186
|
||||
f 113 137 173 185
|
||||
f 112 106 177 183
|
||||
f 164 187 117 195
|
||||
f 154 170 156 192
|
||||
f 148 120 121 167
|
||||
f 165 188 174 189
|
||||
f 76 138 168 183
|
||||
f 116 96 126 178
|
||||
f 76 138 128 168
|
||||
f 82 56 172 187
|
||||
f 172 176 166 193
|
||||
f 9 98 118 164
|
||||
f 30 29 12 171
|
||||
f 70 166 192 193
|
||||
f 33 38 29 171
|
||||
f 165 175 169 188
|
||||
f 96 73 156 170
|
||||
f 141 175 16 194
|
||||
f 96 25 73 178
|
||||
f 45 175 40 188
|
||||
f 98 164 9 196
|
||||
f 121 94 52 190
|
||||
f 106 56 112 172
|
||||
f 70 68 77 166
|
||||
f 70 192 124 193
|
||||
f 169 175 164 196
|
||||
f 31 45 40 188
|
||||
f 172 177 169 187
|
||||
f 106 89 172 183
|
||||
f 113 149 130 173
|
||||
f 149 189 173 197
|
||||
f 121 167 94 190
|
||||
f 171 175 165 191
|
||||
f 93 110 193 195
|
||||
f 172 193 110 195
|
||||
f 125 40 47 191
|
||||
f 3 49 14 177
|
||||
f 96 154 126 170
|
||||
f 78 90 183 193
|
||||
f 152 26 174 189
|
||||
f 113 57 137 185
|
||||
f 16 194 175 196
|
||||
f 60 62 181 182
|
||||
f 110 82 172 195
|
||||
f 92 149 113 173
|
||||
f 146 23 24 177
|
||||
f 34 28 32 188
|
||||
f 163 185 173 186
|
||||
f 72 75 132 186
|
||||
f 91 145 126 170
|
||||
f 38 171 33 191
|
||||
f 124 192 104 193
|
||||
f 18 22 21 187
|
||||
f 77 166 68 192
|
||||
f 130 36 37 189
|
||||
f 30 179 43 190
|
||||
f 131 183 76 184
|
||||
f 89 110 172 193
|
||||
f 121 120 94 167
|
||||
f 9 164 118 194
|
||||
f 173 174 168 197
|
||||
f 12 171 29 194
|
||||
f 56 23 112 177
|
||||
f 116 1 96 178
|
||||
f 17 27 5 188
|
||||
f 140 27 28 188
|
||||
f 104 192 176 193
|
||||
f 120 94 167 190
|
||||
f 112 177 107 183
|
||||
f 82 56 110 172
|
||||
f 169 164 187 196
|
||||
f 164 175 171 194
|
||||
f 118 194 164 198
|
||||
f 3 174 49 177
|
||||
f 9 164 194 196
|
||||
f 70 166 77 192
|
||||
f 167 180 173 185
|
||||
f 146 24 14 177
|
||||
f 30 44 43 179
|
||||
f 101 154 156 192
|
||||
f 152 174 140 189
|
||||
f 166 182 163 184
|
||||
f 92 149 173 197
|
||||
f 171 190 33 191
|
||||
f 60 63 62 182
|
||||
f 45 129 175 188
|
||||
f 163 181 167 185
|
||||
f 150 195 99 198
|
||||
f 167 179 171 190
|
||||
f 143 193 176 195
|
||||
f 164 176 172 195
|
||||
f 171 178 164 194
|
||||
f 164 178 176 198
|
||||
f 9 194 16 196
|
||||
f 129 17 6 188
|
||||
f 78 89 90 193
|
||||
f 10 118 15 194
|
||||
f 10 15 178 194
|
||||
f 150 99 80 198
|
||||
f 83 186 168 197
|
||||
f 111 190 180 191
|
||||
f 77 68 127 192
|
||||
f 127 68 65 182
|
||||
f 118 15 194 198
|
||||
f 10 15 11 178
|
||||
f 19 3 4 174
|
||||
f 9 16 8 196
|
||||
f 45 31 129 188
|
||||
f 30 144 44 179
|
||||
f 149 153 189 197
|
||||
f 40 32 31 188
|
||||
f 159 168 138 183
|
||||
f 124 123 104 192
|
||||
f 89 183 90 193
|
||||
f 104 176 143 193
|
||||
f 62 63 64 182
|
||||
f 137 185 133 186
|
||||
f 178 194 15 198
|
||||
f 47 40 48 191
|
||||
f 89 110 106 172
|
||||
f 75 83 87 186
|
||||
f 123 176 104 192
|
||||
f 105 49 2 168
|
||||
f 107 177 95 183
|
||||
f 87 186 83 197
|
||||
f 173 186 92 197
|
||||
f 73 122 176 198
|
||||
f 159 138 95 183
|
||||
f 149 153 50 189
|
||||
f 112 107 106 183
|
||||
f 137 133 88 186
|
||||
f 120 111 94 190
|
||||
f 110 56 106 172
|
||||
f 93 193 143 195
|
||||
f 170 182 166 192
|
||||
f 173 180 165 189
|
||||
f 10 178 11 194
|
||||
f 114 190 111 191
|
||||
f 52 53 55 179
|
||||
f 173 189 174 197
|
||||
f 139 174 26 189
|
||||
f 19 140 152 174
|
||||
f 116 145 53 179
|
||||
f 36 34 35 189
|
||||
f 100 127 182 192
|
||||
f 116 126 145 179
|
||||
f 134 78 90 183
|
||||
f 112 23 146 177
|
||||
f 89 93 110 193
|
||||
f 115 110 93 195
|
||||
f 63 60 100 182
|
||||
f 159 128 138 168
|
||||
f 11 144 12 178
|
||||
f 46 140 34 189
|
||||
f 168 184 163 186
|
||||
f 16 175 151 196
|
||||
f 106 90 89 183
|
||||
f 76 131 109 183
|
||||
f 41 42 37 180
|
||||
f 2 3 26 174
|
||||
f 143 176 86 195
|
||||
f 70 77 124 192
|
||||
f 137 88 92 186
|
||||
f 16 151 8 196
|
||||
f 73 122 156 176
|
||||
f 3 2 49 174
|
||||
f 150 80 118 198
|
||||
f 155 117 187 195
|
||||
f 160 143 104 176
|
||||
f 84 55 59 181
|
||||
f 25 61 73 198
|
||||
f 33 30 43 190
|
||||
f 166 183 172 193
|
||||
f 105 168 2 197
|
||||
f 107 85 95 177
|
||||
f 150 117 99 195
|
||||
f 79 78 70 193
|
||||
f 141 16 20 194
|
||||
f 16 141 48 175
|
||||
f 111 180 147 191
|
||||
f 45 129 151 175
|
||||
f 86 195 176 198
|
||||
f 156 122 123 176
|
||||
f 122 86 176 198
|
||||
f 11 178 12 194
|
||||
f 29 141 20 194
|
||||
f 92 108 149 197
|
||||
f 156 176 123 192
|
||||
f 82 22 56 187
|
||||
f 160 104 123 176
|
||||
f 95 85 49 177
|
||||
f 48 40 45 175
|
||||
f 84 59 136 181
|
||||
f 51 37 42 180
|
||||
f 105 159 49 168
|
||||
f 13 187 117 196
|
||||
f 43 179 52 190
|
||||
f 139 174 189 197
|
||||
f 134 109 131 183
|
||||
f 160 86 143 176
|
||||
f 96 1 25 178
|
||||
f 114 111 147 191
|
||||
f 59 55 58 181
|
||||
f 19 26 3 174
|
||||
f 99 195 86 198
|
||||
f 110 115 82 195
|
||||
f 155 187 82 195
|
||||
f 60 62 59 181
|
||||
f 71 74 72 184
|
||||
f 25 178 15 198
|
||||
f 158 103 119 185
|
||||
f 152 140 46 189
|
||||
f 175 194 164 196
|
||||
f 43 44 52 179
|
||||
f 164 172 187 195
|
||||
f 59 62 136 181
|
||||
f 100 157 127 192
|
||||
f 93 104 143 193
|
||||
f 15 25 11 178
|
||||
f 59 58 60 181
|
||||
f 73 61 122 198
|
||||
f 99 86 80 198
|
||||
f 54 51 42 180
|
||||
f 102 119 103 185
|
||||
f 67 71 66 184
|
||||
f 71 72 66 184
|
||||
f 39 33 190 191
|
||||
f 64 63 65 182
|
||||
f 152 139 26 189
|
||||
f 160 123 122 176
|
||||
f 39 38 33 191
|
||||
f 132 88 133 186
|
||||
f 21 187 13 196
|
||||
f 92 186 87 197
|
||||
f 124 79 70 193
|
||||
f 2 26 139 174
|
||||
f 76 109 138 183
|
||||
f 114 39 33 190
|
||||
f 38 47 48 191
|
||||
f 117 13 142 187
|
||||
f 142 155 117 187
|
||||
f 153 152 46 189
|
||||
f 25 1 11 178
|
||||
f 41 147 42 180
|
||||
f 42 111 54 180
|
||||
f 98 13 117 196
|
||||
f 122 61 86 198
|
||||
f 105 83 128 168
|
||||
f 176 192 166 193
|
||||
f 107 112 85 177
|
||||
f 122 86 160 176
|
||||
f 41 147 180 191
|
||||
f 76 74 71 184
|
||||
f 13 21 142 187
|
||||
f 2 174 139 197
|
||||
f 131 71 67 184
|
||||
f 85 146 14 177
|
||||
f 142 82 155 187
|
||||
f 36 130 50 189
|
||||
f 97 87 83 197
|
||||
f 87 92 88 186
|
||||
f 41 125 47 191
|
||||
f 42 147 111 180
|
||||
f 83 168 105 197
|
||||
f 155 99 117 195
|
||||
f 155 82 115 195
|
||||
f 45 151 16 175
|
||||
f 57 102 103 185
|
||||
f 49 85 14 177
|
||||
f 158 133 103 185
|
||||
f 39 190 114 191
|
||||
f 44 144 116 179
|
||||
f 115 93 143 195
|
||||
f 8 98 9 196
|
||||
f 1 144 11 178
|
||||
f 63 100 127 182
|
||||
f 168 186 173 197
|
||||
f 146 85 112 177
|
||||
f 139 189 153 197
|
||||
f 108 153 149 197
|
||||
f 52 44 53 179
|
||||
f 32 28 31 188
|
||||
f 44 116 53 179
|
||||
f 108 92 87 197
|
||||
f 21 22 142 187
|
||||
f 176 195 164 198
|
||||
f 90 106 107 183
|
||||
f 10 11 12 194
|
||||
f 138 107 95 183
|
||||
f 82 142 22 187
|
||||
f 28 27 17 188
|
||||
f 7 21 13 196
|
||||
f 131 76 71 184
|
||||
f 100 101 157 192
|
||||
f 176 193 172 195
|
||||
f 20 16 9 194
|
||||
f 152 26 19 174
|
||||
f 88 132 75 186
|
||||
f 164 194 178 198
|
||||
f 129 31 17 188
|
||||
f 57 103 137 185
|
||||
f 127 65 63 182
|
||||
f 159 105 128 168
|
||||
f 139 152 153 189
|
||||
f 138 109 107 183
|
||||
f 137 103 133 185
|
||||
f 79 89 78 193
|
||||
f 94 43 52 190
|
||||
f 16 48 45 175
|
||||
f 25 15 61 198
|
||||
f 36 46 34 189
|
||||
f 12 29 20 194
|
||||
f 75 87 88 186
|
||||
f 77 127 157 192
|
||||
f 9 118 10 194
|
||||
f 111 114 94 190
|
||||
f 97 83 105 197
|
||||
f 99 143 86 195
|
||||
f 80 15 118 198
|
||||
f 8 151 7 196
|
||||
f 124 104 79 193
|
||||
f 134 90 109 183
|
||||
f 39 114 147 191
|
||||
f 33 43 114 190
|
||||
f 79 93 89 193
|
||||
f 77 123 124 192
|
||||
f 36 50 46 189
|
||||
f 79 104 93 193
|
||||
f 31 28 17 188
|
||||
f 97 105 139 197
|
||||
f 61 80 86 198
|
||||
f 139 105 2 197
|
||||
f 109 90 107 183
|
||||
f 8 7 13 196
|
||||
f 143 99 115 195
|
||||
f 98 8 13 196
|
||||
f 47 38 39 191
|
||||
f 41 47 147 191
|
||||
f 153 46 50 189
|
||||
f 157 101 123 192
|
||||
f 94 114 43 190
|
||||
f 115 99 155 195
|
||||
f 157 123 77 192
|
||||
f 12 20 10 194
|
||||
f 156 123 101 192
|
||||
f 61 15 80 198
|
||||
f 20 9 10 194
|
||||
f 47 39 147 191
|
||||
f 97 108 87 197
|
||||
f 139 153 108 197
|
||||
f 139 108 97 197
|
||||
f 181 158 81 136
|
||||
f 181 81 158 163
|
||||
f 69 183 78 134
|
||||
f 78 183 69 166
|
||||
f 185 161 186 163
|
||||
f 185 186 161 133
|
||||
f 180 35 189 37
|
||||
f 180 189 35 165
|
||||
f 179 121 190 167
|
||||
f 179 190 121 52
|
||||
f 177 3 4 14
|
||||
f 177 4 3 174
|
||||
f 55 181 53 58
|
||||
f 55 53 181 179
|
||||
f 145 53 181 58
|
||||
f 145 181 53 179
|
||||
f 100 192 91 101
|
||||
f 100 91 192 170
|
||||
f 154 91 192 101
|
||||
f 154 192 91 170
|
||||
f 196 129 151 7
|
||||
f 196 151 129 175
|
||||
f 189 149 130 50
|
||||
f 189 130 149 173
|
||||
f 116 178 144 1
|
||||
f 116 144 178 179
|
||||
@@ -0,0 +1,278 @@
|
||||
v 0 1 0
|
||||
v 1 1 0
|
||||
v 2 1 0
|
||||
v 3 1 0
|
||||
v 4 1 0
|
||||
v 5 1 0
|
||||
v 6 1 0
|
||||
v 7 1 0
|
||||
v 8 1 0
|
||||
v 9 1 0
|
||||
v 10 1 0
|
||||
v 0 0 0
|
||||
v 1 0 0
|
||||
v 2 0 0
|
||||
v 3 0 0
|
||||
v 4 0 0
|
||||
v 5 0 0
|
||||
v 6 0 0
|
||||
v 7 0 0
|
||||
v 8 0 0
|
||||
v 9 0 0
|
||||
v 10 0 0
|
||||
v 0 1 2
|
||||
v 1 1 2
|
||||
v 2 1 2
|
||||
v 3 1 2
|
||||
v 4 1 2
|
||||
v 5 1 2
|
||||
v 6 1 2
|
||||
v 7 1 2
|
||||
v 8 1 2
|
||||
v 9 1 2
|
||||
v 10 1 2
|
||||
v 0 2 2
|
||||
v 1 2 2
|
||||
v 2 2 2
|
||||
v 3 2 2
|
||||
v 4 2 2
|
||||
v 5 2 2
|
||||
v 6 2 2
|
||||
v 7 2 2
|
||||
v 8 2 2
|
||||
v 9 2 2
|
||||
v 10 2 2
|
||||
v 1 0 1
|
||||
v 2 0 1
|
||||
v 3 0 1
|
||||
v 4 0 1
|
||||
v 5 0 1
|
||||
v 6 0 1
|
||||
v 7 0 1
|
||||
v 8 0 1
|
||||
v 9 0 1
|
||||
v 10 0 1
|
||||
v 0 0 2
|
||||
v 1 0 2
|
||||
v 2 0 2
|
||||
v 3 0 2
|
||||
v 4 0 2
|
||||
v 5 0 2
|
||||
v 6 0 2
|
||||
v 7 0 2
|
||||
v 8 0 2
|
||||
v 9 0 2
|
||||
v 10 0 2
|
||||
v 10 1 1
|
||||
v 10 2 0
|
||||
v 9 2 0
|
||||
v 8 2 0
|
||||
v 7 2 0
|
||||
v 6 2 0
|
||||
v 5 2 0
|
||||
v 4 2 0
|
||||
v 3 2 0
|
||||
v 2 2 0
|
||||
v 1 2 0
|
||||
v 0 2 0
|
||||
v 10 2 1
|
||||
v 9 2 1
|
||||
v 8 2 1
|
||||
v 7 2 1
|
||||
v 6 2 1
|
||||
v 5 2 1
|
||||
v 4 2 1
|
||||
v 3 2 1
|
||||
v 2 2 1
|
||||
v 1 2 1
|
||||
v 0 2 1
|
||||
v 0 1 1
|
||||
v 0 0 1
|
||||
f 36 86 25 24
|
||||
f 1 87 88 89
|
||||
f 12 13 1 45
|
||||
f 85 38 37 26
|
||||
f 87 35 23 24
|
||||
f 48 85 4 47
|
||||
f 61 28 49 60
|
||||
f 46 14 2 3
|
||||
f 9 31 8 52
|
||||
f 85 37 25 26
|
||||
f 19 7 18 51
|
||||
f 61 28 50 49
|
||||
f 49 28 27 60
|
||||
f 85 5 4 73
|
||||
f 3 85 4 74
|
||||
f 28 61 50 29
|
||||
f 32 31 43 79
|
||||
f 23 45 90 89
|
||||
f 28 39 40 82
|
||||
f 10 54 53 21
|
||||
f 48 85 47 26
|
||||
f 48 85 5 4
|
||||
f 7 50 18 51
|
||||
f 50 28 29 6
|
||||
f 85 4 74 73
|
||||
f 88 87 23 89
|
||||
f 77 1 76 87
|
||||
f 13 46 14 2
|
||||
f 1 12 45 90
|
||||
f 87 35 34 23
|
||||
f 1 2 87 89
|
||||
f 9 53 20 21
|
||||
f 29 28 82 6
|
||||
f 29 82 7 6
|
||||
f 48 49 16 5
|
||||
f 25 47 58 46
|
||||
f 15 48 16 4
|
||||
f 16 48 5 4
|
||||
f 2 1 45 89
|
||||
f 1 2 76 87
|
||||
f 8 30 7 51
|
||||
f 35 86 36 24
|
||||
f 45 1 90 89
|
||||
f 76 2 86 87
|
||||
f 80 30 41 81
|
||||
f 85 5 73 84
|
||||
f 30 62 29 51
|
||||
f 50 29 7 6
|
||||
f 23 24 45 89
|
||||
f 77 1 87 88
|
||||
f 76 2 75 86
|
||||
f 48 85 26 27
|
||||
f 2 86 87 24
|
||||
f 3 74 75 86
|
||||
f 3 85 74 86
|
||||
f 3 24 86 2
|
||||
f 2 3 75 86
|
||||
f 23 87 24 89
|
||||
f 30 80 41 42
|
||||
f 28 5 27 83
|
||||
f 30 29 41 81
|
||||
f 47 58 59 26
|
||||
f 15 48 4 47
|
||||
f 88 87 34 23
|
||||
f 87 86 35 24
|
||||
f 13 2 1 45
|
||||
f 55 23 45 90
|
||||
f 86 85 36 25
|
||||
f 13 46 2 45
|
||||
f 46 25 24 57
|
||||
f 5 73 84 72
|
||||
f 36 85 37 25
|
||||
f 3 85 86 25
|
||||
f 25 3 24 86
|
||||
f 85 84 38 27
|
||||
f 10 11 66 54
|
||||
f 59 48 26 27
|
||||
f 48 47 59 26
|
||||
f 46 25 57 58
|
||||
f 23 56 55 45
|
||||
f 85 48 5 27
|
||||
f 85 38 26 27
|
||||
f 23 24 56 45
|
||||
f 46 24 2 45
|
||||
f 3 25 24 46
|
||||
f 3 24 2 46
|
||||
f 24 46 57 45
|
||||
f 24 57 56 45
|
||||
f 87 2 24 89
|
||||
f 24 2 45 89
|
||||
f 47 25 3 46
|
||||
f 3 15 4 47
|
||||
f 10 11 54 22
|
||||
f 14 15 3 47
|
||||
f 46 14 3 47
|
||||
f 49 28 5 27
|
||||
f 48 49 5 27
|
||||
f 47 25 58 26
|
||||
f 85 5 84 27
|
||||
f 47 85 3 26
|
||||
f 9 80 31 79
|
||||
f 47 25 26 3
|
||||
f 3 85 25 26
|
||||
f 85 47 3 4
|
||||
f 48 49 27 60
|
||||
f 59 48 27 60
|
||||
f 31 9 53 52
|
||||
f 50 61 62 29
|
||||
f 33 32 78 66
|
||||
f 31 80 30 42
|
||||
f 40 29 82 81
|
||||
f 63 62 30 51
|
||||
f 30 63 51 52
|
||||
f 41 29 40 81
|
||||
f 33 32 66 54
|
||||
f 9 80 68 69
|
||||
f 82 71 70 7
|
||||
f 5 84 83 72
|
||||
f 32 43 78 79
|
||||
f 29 28 40 82
|
||||
f 5 84 27 83
|
||||
f 33 32 44 78
|
||||
f 9 80 79 68
|
||||
f 8 7 19 51
|
||||
f 28 27 39 83
|
||||
f 28 39 82 83
|
||||
f 28 50 49 6
|
||||
f 65 64 32 53
|
||||
f 82 71 7 6
|
||||
f 29 82 81 7
|
||||
f 81 70 8 7
|
||||
f 84 38 27 83
|
||||
f 27 38 39 83
|
||||
f 32 43 44 78
|
||||
f 9 31 32 79
|
||||
f 31 80 42 79
|
||||
f 31 42 43 79
|
||||
f 67 78 10 11
|
||||
f 32 9 10 53
|
||||
f 62 50 29 51
|
||||
f 71 82 83 6
|
||||
f 49 16 5 17
|
||||
f 81 82 70 7
|
||||
f 50 49 6 17
|
||||
f 79 68 67 10
|
||||
f 79 9 68 10
|
||||
f 50 6 18 17
|
||||
f 78 10 11 66
|
||||
f 78 79 67 10
|
||||
f 32 9 79 10
|
||||
f 78 32 79 66
|
||||
f 79 32 10 66
|
||||
f 78 79 10 66
|
||||
f 9 10 53 21
|
||||
f 82 28 83 6
|
||||
f 71 83 72 6
|
||||
f 69 81 70 8
|
||||
f 64 31 53 52
|
||||
f 28 5 83 6
|
||||
f 83 5 72 6
|
||||
f 80 30 81 8
|
||||
f 28 49 5 6
|
||||
f 64 63 31 52
|
||||
f 80 81 69 8
|
||||
f 9 80 69 8
|
||||
f 7 50 6 18
|
||||
f 80 9 31 8
|
||||
f 80 31 30 8
|
||||
f 31 63 30 52
|
||||
f 31 30 8 52
|
||||
f 30 81 8 7
|
||||
f 30 29 81 7
|
||||
f 19 8 51 52
|
||||
f 33 65 32 54
|
||||
f 49 5 6 17
|
||||
f 10 54 21 22
|
||||
f 29 50 7 51
|
||||
f 30 29 7 51
|
||||
f 65 32 54 53
|
||||
f 9 53 52 20
|
||||
f 31 9 32 53
|
||||
f 64 31 32 53
|
||||
f 32 10 66 53
|
||||
f 66 10 54 53
|
||||
f 32 66 54 53
|
||||
f 8 30 51 52
|
||||
f 8 9 52 20
|
||||
f 19 8 52 20
|
||||
File diff suppressed because it is too large.
Load diff
+387
@@ -0,0 +1,387 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import torch\n",
|
||||
"import igl\n",
|
||||
"\n",
|
||||
"import meshplot as mp\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticenergy import *\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from adjoint_sensitivity import *\n",
|
||||
"from vis_utils import *\n",
|
||||
"from objectives import *\n",
|
||||
"from harmonic_interpolator import *\n",
|
||||
"from shape_optimizer import *\n",
|
||||
"\n",
|
||||
"from utils import *\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"torch.set_default_dtype(torch.float64)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Create the deformed object\n",
|
||||
"\n",
|
||||
"## Load the mesh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "9ae930440a43419c88fd82d71d7a6fa4",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<meshplot.Viewer.Viewer at 0x7f86840382e0>"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/dinosaur.obj\")\n",
|
||||
"# vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
|
||||
"\n",
|
||||
"aabb = np.max(vNP, axis=0) - np.min(vNP, axis=0)\n",
|
||||
"length_scale = np.mean(aabb)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"v, t = torch.tensor(vNP), torch.tensor(tNP)\n",
|
||||
"eNP = igl.edges(tNP)\n",
|
||||
"beNP = igl.edges(igl.boundary_facets(tNP))\n",
|
||||
"\n",
|
||||
"bvNP, ivNP = get_boundary_and_interior(v.shape[0], tNP)\n",
|
||||
"\n",
|
||||
"mp.plot(vNP @ rot.T, np.array(tNP), shading=shadingOptions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Add some physical characteristics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Pinned vertices: [ 46 47 50 59 60 62 64 65 88 89 91 98 99 102 103 104]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3], if aabb[0] ~ 14m, and m_tot = 6000kg\n",
|
||||
"young = 3e8 # [Pa] \n",
|
||||
"poisson = 0.2\n",
|
||||
"\n",
|
||||
"# Find some of the lowest vertices and pin them\n",
|
||||
"minZ = torch.min(v[:, 2])\n",
|
||||
"pin_idx = torch.arange(v.shape[0])[v[:, 2] < minZ + 0.01*aabb[2]]\n",
|
||||
"vIdx = np.arange(v.shape[0])\n",
|
||||
"pin_idx = vIdx[np.in1d(vIdx, bvNP) & np.in1d(vIdx, pin_idx)]\n",
|
||||
"print(\"Pinned vertices: {}\".format(pin_idx))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Initial guess\n",
|
||||
"\n",
|
||||
"The idea is that we start deforming the mesh by inverting gravity."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "1ee888e94cd641f4bbbce4b051acccfb",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-2.468079…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Inverted gravity\n",
|
||||
"force_mass = torch.zeros(size=(3,))\n",
|
||||
"force_mass[2] = + rho * 9.81\n",
|
||||
"\n",
|
||||
"# Gravity going in the wrong direction\n",
|
||||
"\n",
|
||||
"ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"\n",
|
||||
"v = HarmonicInterpolator(v, t, ivNP).interpolate(v[bvNP])\n",
|
||||
"solid_init = ElasticSolid(v, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
|
||||
"\n",
|
||||
"solid_init.find_equilibrium()\n",
|
||||
"plot_torch_solid(solid_init, beNP, rot, length_scale)\n",
|
||||
"\n",
|
||||
"# Use these as initial guesses\n",
|
||||
"v_init_rest = solid_init.v_def.clone().detach()\n",
|
||||
"v_init_def = solid_init.v_rest.clone().detach()\n",
|
||||
"\n",
|
||||
"# v_init_rest = solid_init.v_rest.clone().detach()\n",
|
||||
"# v_init_def = solid_init.v_def.clone().detach()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Inverse design\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "TypeError",
|
||||
"evalue": "unsupported format string passed to NoneType.__format__",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
|
||||
"\u001b[0;32m/tmp/ipykernel_46/1868162750.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0msolid_\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mupdate_def_shape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv_init_def\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m \u001b[0moptimizer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mShapeOptimizer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msolid_\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvt_surf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mweight_reg\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0.\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 17\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mv_eq_init\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0moptimizer\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msolid\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mv_def\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclone\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdetach\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m#bookkeeping\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
|
||||
"\u001b[0;32m/opt/notebooks/assignment_2_4/notebook/../src/shape_optimizer.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, solid, vt_surf, weight_reg)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msolid\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfind_equilibrium\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0mobj_init\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtgt_fit\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msolid\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mv_def\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclone\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdetach\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Initial objective: {:.4e}\\n\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobj_init\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 51\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 52\u001b[0m \u001b[0;31m# Initialize grad\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
|
||||
"\u001b[0;31mTypeError\u001b[0m: unsupported format string passed to NoneType.__format__"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"force_mass = torch.zeros(size=(3,))\n",
|
||||
"force_mass[2] = - rho * 9.81\n",
|
||||
"use_linear = False\n",
|
||||
"\n",
|
||||
"# The target is the initial raw mesh\n",
|
||||
"vt_surf = torch.tensor(vNP[bvNP, :])\n",
|
||||
"\n",
|
||||
"# Create solid\n",
|
||||
"if use_linear:\n",
|
||||
" ee = LinearElasticEnergy(young, poisson)\n",
|
||||
"else:\n",
|
||||
" ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"solid_ = ElasticSolid(v_init_rest, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
|
||||
"solid_.update_def_shape(v_init_def)\n",
|
||||
"\n",
|
||||
"optimizer = ShapeOptimizer(solid_, vt_surf, weight_reg=0.)\n",
|
||||
"\n",
|
||||
"v_eq_init = optimizer.solid.v_def.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"optimizer.optimize(step_size_init=1e-4, max_l_iter=10, n_optim_steps=40)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(10, 6))\n",
|
||||
"plt.plot(to_numpy(optimizer.objectives[optimizer.objectives > 0]))\n",
|
||||
"plt.title(\"Objective as optimization goes\", fontsize=14)\n",
|
||||
"plt.xlabel(\"Optimization steps\", fontsize=12)\n",
|
||||
"plt.ylabel(\"Objective\", fontsize=12)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Green (Initial guess for rest state) deploys to Black\n",
|
||||
"\n",
|
||||
"Blue (Optimized rest state) deploys to Yellow\n",
|
||||
"\n",
|
||||
"Red is the Target Shape\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
|
||||
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
|
||||
"p.add_edges(np.array(v_init_rest) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
|
||||
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
|
||||
"p.add_edges(np.array(v_eq_init) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
|
||||
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"v_rest_optim_g = optimizer.solid.v_rest.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Add point load to the right most vertices\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"maxX = torch.min(v[:, 0])\n",
|
||||
"f_point_idx = torch.arange(v.shape[0])[v[:, 0] > maxX - 0.01*aabb[0]]\n",
|
||||
"\n",
|
||||
"f_point = torch.zeros(size=(f_point_idx.shape[0], 3))\n",
|
||||
"f_point[:, 2] = -5e3\n",
|
||||
"\n",
|
||||
"optimizer.solid.add_point_load(f_point_idx, f_point)\n",
|
||||
"optimizer.set_params(optimizer.params)\n",
|
||||
"v_def_optim_g_under_point = optimizer.solid.v_def.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"optimizer.reset_BFGS()\n",
|
||||
"optimizer.optimize(step_size_init=1e-4, max_l_iter=10, n_optim_steps=20)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Green (Optimum rest state under gravity) deploys to Black with the additional point load\n",
|
||||
"\n",
|
||||
"Blue (Optimized rest state) deploys to Yellow\n",
|
||||
"\n",
|
||||
"Red is the Target Shape\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
|
||||
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
|
||||
"p.add_edges(np.array(v_rest_optim_g) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
|
||||
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
|
||||
"p.add_edges(np.array(v_def_optim_g_under_point) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
|
||||
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Description\n",
|
||||
"\n",
|
||||
"This notebook intends to gather all the functionalities you'll have to implement for assignment 2.2.\n",
|
||||
"\n",
|
||||
"# Load libraries"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import igl\n",
|
||||
"import meshplot as mp\n",
|
||||
"import time\n",
|
||||
"import torch\n",
|
||||
"\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from elasticenergy import *\n",
|
||||
"from vis_utils import *\n",
|
||||
"from matplotlib import gridspec\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"torch.set_default_dtype(torch.float64)\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Load mesh\n",
|
||||
"\n",
|
||||
"Several meshes are available for you to play with under `data/`: `ball.obj`, `dinosaur.obj`, and `beam.obj`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
|
||||
"aabb = np.max(vNP, axis=0) - np.min(vNP, axis=0)\n",
|
||||
"v = torch.tensor(vNP)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Linear/Non-Linear Elastic Solid\n",
|
||||
"\n",
|
||||
"## Instantiation\n",
|
||||
"\n",
|
||||
"We first specify the elasticity model to use for the elastic solid, as well as pinned vertices, and volumetric forces."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3]\n",
|
||||
"young = 10e6 # [Pa] \n",
|
||||
"poisson = 0.2\n",
|
||||
"force_mass = torch.zeros(size = (3,))\n",
|
||||
"force_mass[2] = - rho * 9.81\n",
|
||||
"\n",
|
||||
"minX = torch.min(v[:, 0])\n",
|
||||
"pin_idx = torch.arange(v.shape[0])[v[:, 0] < minX + 0.2*aabb[0]]\n",
|
||||
"\n",
|
||||
"# ee = LinearElasticEnergy(young, poisson)\n",
|
||||
"ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"solid = ElasticSolid(v, tNP, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Validate Elastic Energy Gradient (Elastic Forces) using Finite Differences on Elastic Energy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"solid.update_def_shape(v)\n",
|
||||
"\n",
|
||||
"fd_validation_elastic(solid)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Validate External Energy Gradient (External Forces) using Finite Differences on External Energy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAYEAAAD8CAYAAACRkhiPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAABFnklEQVR4nO3deXyc1Xnw/d81I41Gy2i3dkvyvhsbG7ODQiAxCQSakATI1oaEJi3t2z5Nn5K2T5O3T3lJkzZpk9CkBChJ2kAIIWEJgYRFmB2DDcbGlhfZlrXvy0gajUZz3j9m0Yw0I400I1kjXd/PRx80933PPeeg8VxzznUWMcaglFJqabKc7QIopZQ6ezQIKKXUEqZBQCmlljANAkoptYRpEFBKqSVMg4BSSi1hKWe7ADNRWFhoqqurZ/38wcFBMjMzE1egs2Sx1AO0LgvRYqkHaF0C3nrrrU5jzLJI55IqCFRXV/Pmm2/O+vm1tbXU1NQkrkBnyWKpB2hdFqLFUg/QugSIyOlo55KiO0hErhWRu/v6+s52UZRSalFJiiBgjHncGHNrTk7O2S6KUkotKkkRBJRSSs0NDQJKKbWEaRBQSqklLCmCgCaGlVJqbiRFEDjbieHm3mE6BkbOymsrpdRcSoogEK8ht4c3TnbT75753gler+HGu1/jK794Zw5KppRSZ9eSCAIN3UN84j9f5Uj32Iyfu+dYBw3dQ+w73YPXqxvwKKUWlyURBPIzbQAMTNMSiLTL2s9eb/A9d8TDiQ5n4gunlFJn0VkNAiJyqYj8UETuEZFX5up18jJ8QcA5TRC45nsv8c9PHQk+but38eyRdq7cUATA/jO9c1VEpZQ6K2YdBETkPhFpF5GDE47vFpE6ETkuIrdPdQ9jzIvGmC8BTwA/nm1ZppNqtZBtT5kyJ+D2eDnU3M8Pak/w4rEOAB7ae4Yxr+FvP7QBhz2FtzUIKKUWmXhaAvcDu0MPiIgVuAu4GtgI3CQiG0Vki4g8MeGnKOSpNwMPxFGWaeVn2qZsCXQPugEQga/84h26nCM8uPcMF68uYOWyLM6pyOXtht65LKJSSs27WQcBY8weoHvC4V3AcWNMvTHGDTwIXGeMedcYc82En3YAEakE+owx/bMtSyzyM20MjEYPAp1O3xDQP3vfaroH3Xzy7tdo6h3m5l1VAGxbnktd2wDD7pknl5VSaqFK9FLS5cCZkMeNwPnTPOcW4L+inRSRW4FbAYqLi6mtrZ1VwYzLRd/wWNTnH+jwAOAYbOS6VSk8fNRJtg3SOo9QW1uHtc/DmNfwkydqWZdvnVUZEsXpdM76/8NCo3VZeBZLPUDrEotEBwGJcGzKbKwx5mvTnL9bRFqAax0Ox47Zrqf9ZOc7nHy3Kep63F1vNcJb73DVpRfw+fwMLI8cYGdVPleetxyAzc4R/n3fM0hhNTWXrZpVGRJF10hfmBZLXRZLPUDrEotEjw5qBJaHPK4AmuO9aSJmDOdnpjHgNhGHgQJ0Dfq6gwqybFgtwjdvOIdPnDdelcKsNCry0jU5rJRaVBIdBPYCa0RkhYjYgBuBx+K9aSLWDsrPTGXMgHPEE/F8p9NNWoqFrLTojaNtyzU5rJRaXOIZIvoA8CqwTkQaReQWY4wHuA14GjgMPGSMOZSYosYnPzMNGB8FNFGnc4TCrDREIvVo+Wxbnktzn4v2fteclFEppeZbPKODbjLGlBpjUo0xFcaYe/3HnzTGrDXGrDLG3JGIQiamOygViB4EupxuCrJsU95je2UugHYJKaUWjaRYNiIx3UGxtQSmsqkshxSLhAWB3iE3Lx7r4D9qjweXmFBKqWSR6NFBc8IY8zjw+M6dO78423sU+NcPmqolsLE0e8p72FOtbCjN5j9qT3D3nnpEYHQsPNF8XnUea4odsy2mUkrNq6QIAiJyLXDt6tWrZ32PvCmCgDGGrsERCqZpCQB8/SMbee5IO8aA10B2egpby3Mpz0vn6n/fwz0vnuSfb9g663IqpdR8SoogkIiWQKbNSoolchDoH/YwOmYonCYnALCjKp8dVfkRz92wo4KH9jbyVx9YS1G2fbZFVUqpeZMUOYFEEBEcqRIxCHT65whMlxOYzhcuWcmo18v9r5yK6z5KKTVfkiIIJGqPYYctchDocvqOTTc6aDrVhZns3lTCf792Oup8BKWUWkiSIggkao9hhw26hyK0BJyJaQkAfPGylfS7PDy098z0Fyul1FmWFEEgUaK3BMaXjIjXuZV5nFedx70vncQz5o3pOWNew8/3NuAa1RVKlVLza0kFgawoOYEOpxsRyM+IPwgAfOHSlTT1DvP799piuv7Zw238zS/f5fkj7Ql5faWUilVSBIFE5gQGXB7cnvBv6F3OEfIybKRYE/O/48oNxVTkpfNfL5+K6fpnD/s+/Jt6hxPy+kopFaukCAKJywn41gXqnZAX6HK6g5PJEsFqET53YTVvnOrmYNPUgcvrNTxX5wsCzb26JpFSan4lRRBIlEAQ6JrQJRTLkhEz9YnzlpOeap12uOjB5j46Bnw5idZ+bQkopebXkgwCE/MCXYPTLx43UznpqXxsRzmPvd0cHH0UyTOH27EIbCrL1paAUmreLa0gkBo5CMxFSwDgDy9agXvMywOvN9DUO8xPXzvNPz3xHkPu8TkEzx1pY0dVHhtLs2np05aAUmp+JcWyEYlYOwgitwRco2MMuDwxLRkxU6uLsrhs7TL+/dlj/OvvjwaPj3i8/N/rN9Pa5+JgUz9/s3s9w6NjtA+MMDrmJTVBCWqllJpOUgSBRKwdBODfUiAsCAR+j2XxuNn4q6vWkmoRzl+ZzxXri3ngjQbufekkV24spqnH983//RuK2He6B2Ogrd9FRV7GnJRFKaUmSoogkChWi5CbkRoWBIJLRiRwdFCoc5bncu8fnhd8/NcfXMeeox389S/eobowk4q8dNYUZdHsHx7a0jceBEY8Y3zsB69w2/vWsHtzyZyUTym1tC25fof8TFvY0hHBJSMcc9MSmMieauU7n9xG96CbN0528/71RYgIZbnpAMFgAFDfMcjBpn7+7ZmjGGOi3VIppWZt6QWBDBvdzghBIHN+ggDA5vIc/uLKNQBctdH3Db80x7f0dEvf+AihY+1OAI60DvBaffe8lU8ptXSc1e4gEakEvg90AkeNMd+Y69fMz7TR0D0UfByYM1DomJvuoGj+pGY1F68uZNvyXAAc9lQcaSm0hLQEjrcNYBHITk/lv14+yYWrCua1jEqpxW/WLQERuU9E2kXk4ITju0WkTkSOi8jt09xmLfAbY8zngY2zLctM5GfawiaLdQ6MkJ5qJcM2v/HQYhG2V+YhIsFjpbl2mie0BKoLMrl5VyW/P9zGmZDgFc2DbzTwyL7GOSmzUmrxiac76H5gd+gBEbECdwFX4/tQv0lENorIFhF5YsJPEbAfuFFEngOej6MsMcvPtNEz6A72sc/FRLHZKs1Jp3VCEFhdlMVnLqzCIsJPXj015fOdIx7+8Yn3+LFuaqOUitGsv/4aY/aISPWEw7uA48aYegAReRC4zhhzJ3DNxHuIyFeAr/nv9TDwXxGuuRW4FaC4uJja2trZFhmn00l3xxk8XsOTz9SSmSoca3Bh85q47pswQyOc7vBQW1uLx2s42THE+qwR6va/zo4iC//96kl2pLXhcQ1GLO8LZ0YZco/R2Nm/MOoTA6fTmTRlnc5iqctiqQdoXWKR6D6QciB0N5VG4Pwprn8K+LqI3AycinSBMeZu4G6AnTt3mpqamlkXrra2ll1lq3mw7h02bt/FisJM/vmdF1lZZKem5rzpbzDHDowd44XGo1x4yaWc7hpi7Hd7uPK8TdRsL8exooeP/eAVvn84hTxSuWBzBddvL6fcP6oI4N/uehlwM+ARLr/88rCupniMjnn5n9dOc+OuSuyp1oTcM6C2tpZ4/qYLyWKpy2KpB2hdYpHo0UGRPnWijm00xhw0xtxgjPmSMeYrUW+aoKWkwdcdBOOTxLqcIxTM48igqQRGCLX2uTjW5hsZtLooC4BzK3P5ygfWkp5q5UDnGN96uo7P3fdGcCOaI639vH2ml4q8dNweLwMJ3N5y78luvv74ezyyrylh91RKLQyJDgKNwPKQxxVAc4JfIy6BIPBafRffffYYXYPueR8ZFM34XAEXx9oHEBkPAiLCbVes4Rdfuoh/f18GP/n8Lo63O/m2fzmKB984g81q4Y8uXgH4Et6J0uEfRvvbgy0Ju6dSamFIdBDYC6wRkRUiYgNuBB6L96aJ2k8AxpeH+NbTdXznmaNsKsvmg5sWxmzc8bkCwxxrd1KZnxG1++Wytcu4+fxKfvRiPS8f7+RX+5v4wKZi1viDRqdz8g5qsxWYVf3qiS76hkYTdl+l1Nk365yAiDwA1ACFItKIL8F7r4jcBjwNWIH7jDGH4i1kohaQAyjLsfP/fmQTuRmpXLK6cM7WDJqN0hxfS6Clz8XxNmfwAz2av/3QBvYc7eCWH+/FNerlxvMqgy2dqZavnqlA15nHa3jmcBsf21EBgDGGF491cm5VHllpS2oFEqUWjVm3BIwxNxljSo0xqcaYCmPMvf7jTxpj1hpjVhlj7khEIRPZEhARPndRNddtK19QAQAg3WYlNyOVM91D1Hc6WV3kmPL6rLQU/uXj5+Aa9bI8P52LVhUEu7ZiDQJH2wb4l6frplyWomvQt9R2WY6d3x5sDR5/vq6dz973Bg++0RDTaymlFp6k+PqWyJbAQleak85r9V2MjplpWwIAF6ws4Js3bKU4247FIuRn2BCJPSfwg9oT/Gp/E394cXXUPRU6nW4Ks2xcuKqA/3m9AeeIB5vVwj89cRjwLWuhlEpOSbF2UCJbAgtdWY6dU12+mcFriqcPAgCf2Lmcy9cuAyDFaiE/w0ZHDDkBt8fLs4fbgKlbDl3OEQqybFy9uRS3x8vzR9r5yaunqO8cJD/TxtE2DQJKJSttCSwwpbn24O+rlsULine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"maxX = torch.max(v[:, 0])\n",
|
||||
"f_point_idx = torch.arange(v.shape[0])[v[:, 0] > maxX - 0.01*aabb[0]]\n",
|
||||
"\n",
|
||||
"f_point = torch.zeros(size=(f_point_idx.shape[0], 3))\n",
|
||||
"f_point[:, 2] = -5e3\n",
|
||||
"\n",
|
||||
"solid.add_point_load(f_point_idx, f_point)\n",
|
||||
"\n",
|
||||
"solid.update_def_shape(v)\n",
|
||||
"\n",
|
||||
"fd_validation_ext(solid)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Validate Elastic Energy Force Differentials (Elastic Forces) using Finite Differences on Elastic Forces"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"solid.update_def_shape(v)\n",
|
||||
"\n",
|
||||
"fd_validation_elastic_differentials(solid)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import torch\n",
|
||||
"import igl\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"import meshplot as mp\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticenergy import *\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from adjoint_sensitivity import *\n",
|
||||
"from vis_utils import *\n",
|
||||
"from objectives import *\n",
|
||||
"from harmonic_interpolator import *\n",
|
||||
"from shape_optimizer import *\n",
|
||||
"\n",
|
||||
"from utils import *\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"torch.set_default_dtype(torch.float64)\n",
|
||||
"\n",
|
||||
"def to_numpy(tensor):\n",
|
||||
" return tensor.detach().clone().numpy()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Create the deformed object\n",
|
||||
"\n",
|
||||
"## Load the mesh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "732bc7276b654a1db0b501b750c8fd87",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0, 1.0,…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<meshplot.Viewer.Viewer at 0x7f4f18719760>"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
|
||||
"\n",
|
||||
"aabb = np.max(vNP, axis=0) - np.min(vNP, axis=0)\n",
|
||||
"length_scale = np.mean(aabb)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"v, t = torch.tensor(vNP), torch.tensor(tNP)\n",
|
||||
"eNP = igl.edges(tNP)\n",
|
||||
"beNP = igl.edges(igl.boundary_facets(tNP))\n",
|
||||
"\n",
|
||||
"def get_boundary_and_interior(vlen, t):\n",
|
||||
" bv = np.unique(igl.boundary_facets(t))\n",
|
||||
" vIdx = np.arange(vlen)\n",
|
||||
" iv = vIdx[np.invert(np.in1d(vIdx, bv))]\n",
|
||||
" return bv, iv\n",
|
||||
"# Compute boundary vertices and interior vertex indices\n",
|
||||
"bvNP, ivNP = get_boundary_and_interior(v.shape[0], tNP)\n",
|
||||
"\n",
|
||||
"mp.plot(vNP @ rot.T, np.array(tNP), shading=shadingOptions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Add some physical characteristics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Pinned vertices: [ 0 1 11 12 22 23 33 34 44 54 55 75 76 86 87 88 89]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3]\n",
|
||||
"damping = 0.\n",
|
||||
"young = 5e7 # [Pa] \n",
|
||||
"poisson = 0.2\n",
|
||||
"\n",
|
||||
"# Find some of the lowest vertices and pin them\n",
|
||||
"minX = torch.min(v[:, 0])\n",
|
||||
"pin_idx = torch.arange(v.shape[0])[v[:, 0] < minX + 0.2*aabb[0]]\n",
|
||||
"vIdx = np.arange(v.shape[0])\n",
|
||||
"pin_idx = vIdx[np.in1d(vIdx, bvNP) & np.in1d(vIdx, pin_idx)]\n",
|
||||
"print(\"Pinned vertices: {}\".format(pin_idx))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Initial guess\n",
|
||||
"\n",
|
||||
"The idea is that we start deforming the mesh by inverting gravity."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "f4fe02d4e90b47cea101747098c5b3bd",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(4.9017367…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Inverted gravity\n",
|
||||
"force_mass = torch.zeros(size=(3,))\n",
|
||||
"force_mass[2] = + rho * 9.81\n",
|
||||
"\n",
|
||||
"# Gravity going in the wrong direction\n",
|
||||
"\n",
|
||||
"ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"\n",
|
||||
"v = HarmonicInterpolator(v, t, ivNP).interpolate(v[bvNP])\n",
|
||||
"solid_init = ElasticSolid(v, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
|
||||
"\n",
|
||||
"solid_init.find_equilibrium()\n",
|
||||
"plot_torch_solid(solid_init, beNP, rot, length_scale)\n",
|
||||
"\n",
|
||||
"# Use these as initial guesses\n",
|
||||
"v_init_rest = solid_init.v_def.clone().detach()\n",
|
||||
"v_init_def = solid_init.v_rest.clone().detach()\n",
|
||||
"\n",
|
||||
"# v_init_rest = solid_init.v_rest.clone().detach()\n",
|
||||
"# v_init_def = solid_init.v_def.clone().detach()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Inverse design\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Initial objective: 1.6230e+00\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"force_mass = torch.zeros(size=(3,))\n",
|
||||
"force_mass[2] = - rho * 9.81\n",
|
||||
"use_linear = False\n",
|
||||
"\n",
|
||||
"# The target is the initial raw mesh\n",
|
||||
"vt_surf = torch.tensor(vNP[bvNP, :])\n",
|
||||
"\n",
|
||||
"# Create solid\n",
|
||||
"if use_linear:\n",
|
||||
" ee = LinearElasticEnergy(young, poisson)\n",
|
||||
"else:\n",
|
||||
" ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"solid_ = ElasticSolid(v_init_rest, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
|
||||
"solid_.update_def_shape(v_init_def)\n",
|
||||
"\n",
|
||||
"optimizer = ShapeOptimizer(solid_, vt_surf, weight_reg=10.)\n",
|
||||
"\n",
|
||||
"v_eq_init = optimizer.solid.v_def.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Objective after 40 optimization step(s): 1.5788e+00\n",
|
||||
" Line search Iters: 9\n",
|
||||
"Elapsed time: 97.1s. \n",
|
||||
"Estimated remaining time: 0.0s\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "10cffc9c94334b8aa1529d4b6fb36278",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0444669…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"optimizer.optimize(step_size_init=1e-2, max_l_iter=10, n_optim_steps=40)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 720x432 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(10, 6))\n",
|
||||
"plt.plot(to_numpy(optimizer.objectives[optimizer.objectives > 0]))\n",
|
||||
"plt.title(\"Objective as optimization goes\", fontsize=14)\n",
|
||||
"plt.xlabel(\"Optimization steps\", fontsize=12)\n",
|
||||
"plt.ylabel(\"Objective\", fontsize=12)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Green (Initial guess for rest state) deploys to Black\n",
|
||||
"\n",
|
||||
"Blue (Optimized rest state) deploys to Yellow\n",
|
||||
"\n",
|
||||
"Red is the Target Shape\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "cc0e6ec0eb174783a516c85f67697225",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0444669…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"4"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
|
||||
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
|
||||
"p.add_edges(np.array(v_init_rest) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
|
||||
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
|
||||
"p.add_edges(np.array(v_eq_init) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
|
||||
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"v_rest_optim_g = optimizer.solid.v_rest.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Add point load to the right most vertices\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"maxX = torch.min(v[:, 0])\n",
|
||||
"f_point_idx = torch.arange(v.shape[0])[v[:, 0] > maxX - 0.01*aabb[0]]\n",
|
||||
"\n",
|
||||
"f_point = torch.zeros(size=(f_point_idx.shape[0], 3))\n",
|
||||
"f_point[:, 2] = -5e4\n",
|
||||
"\n",
|
||||
"optimizer.solid.add_point_load(f_point_idx, f_point)\n",
|
||||
"optimizer.set_params(optimizer.params)\n",
|
||||
"v_def_optim_g_under_point = optimizer.solid.v_def.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Objective after 21 optimization step(s): 2.2335e+01\n",
|
||||
" Line search Iters: 9\n",
|
||||
"Elapsed time: 2215.2s. \n",
|
||||
"Estimated remaining time: 8333.3s\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "f0b258afc95d4bdf8e8bb0e3fb529d05",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(5.0945925…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"optimizer.reset_BFGS()\n",
|
||||
"optimizer.optimize(step_size_init=1e-2, max_l_iter=10, n_optim_steps=100)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Green (Optimum rest state under gravity) deploys to Black with the additional point load\n",
|
||||
"\n",
|
||||
"Blue (Optimized rest state) deploys to Yellow\n",
|
||||
"\n",
|
||||
"Red is the Target Shape\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
|
||||
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
|
||||
"p.add_edges(np.array(v_rest_optim_g) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
|
||||
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
|
||||
"p.add_edges(np.array(v_def_optim_g_under_point) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
|
||||
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import torch\n",
|
||||
"import igl\n",
|
||||
"\n",
|
||||
"import meshplot as mp\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticenergy import *\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from adjoint_sensitivity import *\n",
|
||||
"from vis_utils import *\n",
|
||||
"from objectives import *\n",
|
||||
"from harmonic_interpolator import *\n",
|
||||
"from shape_optimizer import *\n",
|
||||
"\n",
|
||||
"from utils import *\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"torch.set_default_dtype(torch.float64)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Create the deformed object\n",
|
||||
"\n",
|
||||
"## Load the mesh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "35cf42b4eded4cb99f3811a16dcb4d67",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-1.987469…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<meshplot.Viewer.Viewer at 0x7fa5b879cc10>"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/dinosaur.obj\")\n",
|
||||
"# vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
|
||||
"\n",
|
||||
"aabb = np.max(vNP, axis=0) - np.min(vNP, axis=0)\n",
|
||||
"length_scale = np.mean(aabb)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"v, t = torch.tensor(vNP), torch.tensor(tNP)\n",
|
||||
"eNP = igl.edges(tNP)\n",
|
||||
"beNP = igl.edges(igl.boundary_facets(tNP))\n",
|
||||
"\n",
|
||||
"bvNP, ivNP = get_boundary_and_interior(v.shape[0], tNP)\n",
|
||||
"\n",
|
||||
"mp.plot(vNP @ rot.T, np.array(tNP), shading=shadingOptions)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Add some physical characteristics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Pinned vertices: [ 46 47 50 59 60 62 64 65 88 89 91 98 99 102 103 104]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3], if aabb[0] ~ 14m, and m_tot = 6000kg\n",
|
||||
"young = 3e8 # [Pa] \n",
|
||||
"poisson = 0.2\n",
|
||||
"\n",
|
||||
"# Find some of the lowest vertices and pin them\n",
|
||||
"minZ = torch.min(v[:, 2])\n",
|
||||
"pin_idx = torch.arange(v.shape[0])[v[:, 2] < minZ + 0.01*aabb[2]]\n",
|
||||
"vIdx = np.arange(v.shape[0])\n",
|
||||
"pin_idx = vIdx[np.in1d(vIdx, bvNP) & np.in1d(vIdx, pin_idx)]\n",
|
||||
"print(\"Pinned vertices: {}\".format(pin_idx))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Initial guess\n",
|
||||
"\n",
|
||||
"The idea is that we start deforming the mesh by inverting gravity."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "5d62f192ccc940388718972e4a447f2b",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-2.468080…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Inverted gravity\n",
|
||||
"force_mass = torch.zeros(size=(3,))\n",
|
||||
"force_mass[2] = + rho * 9.81\n",
|
||||
"\n",
|
||||
"# Gravity going in the wrong direction\n",
|
||||
"\n",
|
||||
"ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"\n",
|
||||
"v = HarmonicInterpolator(v, t, ivNP).interpolate(v[bvNP])\n",
|
||||
"solid_init = ElasticSolid(v, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
|
||||
"\n",
|
||||
"solid_init.find_equilibrium()\n",
|
||||
"plot_torch_solid(solid_init, beNP, rot, length_scale)\n",
|
||||
"\n",
|
||||
"# Use these as initial guesses\n",
|
||||
"v_init_rest = solid_init.v_def.clone().detach()\n",
|
||||
"v_init_def = solid_init.v_rest.clone().detach()\n",
|
||||
"\n",
|
||||
"# v_init_rest = solid_init.v_rest.clone().detach()\n",
|
||||
"# v_init_def = solid_init.v_def.clone().detach()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Inverse design\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Initial objective: 6.6351e+02\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"force_mass = torch.zeros(size=(3,))\n",
|
||||
"force_mass[2] = - rho * 9.81\n",
|
||||
"use_linear = False\n",
|
||||
"\n",
|
||||
"# The target is the initial raw mesh\n",
|
||||
"vt_surf = torch.tensor(vNP[bvNP, :])\n",
|
||||
"\n",
|
||||
"# Create solid\n",
|
||||
"if use_linear:\n",
|
||||
" ee = LinearElasticEnergy(young, poisson)\n",
|
||||
"else:\n",
|
||||
" ee = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"solid_ = ElasticSolid(v_init_rest, t, ee, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
|
||||
"solid_.update_def_shape(v_init_def)\n",
|
||||
"\n",
|
||||
"optimizer = ShapeOptimizer(solid_, vt_surf, weight_reg=0.)\n",
|
||||
"\n",
|
||||
"v_eq_init = optimizer.solid.v_def.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Objective after 19 optimization step(s): 5.8586e+02\n",
|
||||
" Line search Iters: 8\n",
|
||||
"Elapsed time: 683.7s. \n",
|
||||
"Estimated remaining time: 755.7s\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "fa1a13b5101d4629a3d07e84205409dd",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-0.497634…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"An exception occured: . \n",
|
||||
"Halving the step.\n",
|
||||
"Line search can't find a step to take\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"optimizer.optimize(step_size_init=1e-4, max_l_iter=10, n_optim_steps=40)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 720x432 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(10, 6))\n",
|
||||
"plt.plot(to_numpy(optimizer.objectives[optimizer.objectives > 0]))\n",
|
||||
"plt.title(\"Objective as optimization goes\", fontsize=14)\n",
|
||||
"plt.xlabel(\"Optimization steps\", fontsize=12)\n",
|
||||
"plt.ylabel(\"Objective\", fontsize=12)\n",
|
||||
"plt.grid()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Green (Initial guess for rest state) deploys to Black\n",
|
||||
"\n",
|
||||
"Blue (Optimized rest state) deploys to Yellow\n",
|
||||
"\n",
|
||||
"Red is the Target Shape\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"application/vnd.jupyter.widget-view+json": {
|
||||
"model_id": "70afc138cf264b47b4fddfd6b9ae8624",
|
||||
"version_major": 2,
|
||||
"version_minor": 0
|
||||
},
|
||||
"text/plain": [
|
||||
"Renderer(camera=PerspectiveCamera(children=(DirectionalLight(color='white', intensity=0.6, position=(-0.497634…"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"4"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
|
||||
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
|
||||
"p.add_edges(np.array(v_init_rest) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
|
||||
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
|
||||
"p.add_edges(np.array(v_eq_init) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
|
||||
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"v_rest_optim_g = optimizer.solid.v_rest.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Add point load to the right most vertices\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"maxX = torch.min(v[:, 0])\n",
|
||||
"f_point_idx = torch.arange(v.shape[0])[v[:, 0] > maxX - 0.01*aabb[0]]\n",
|
||||
"\n",
|
||||
"f_point = torch.zeros(size=(f_point_idx.shape[0], 3))\n",
|
||||
"f_point[:, 2] = -5e3\n",
|
||||
"\n",
|
||||
"optimizer.solid.add_point_load(f_point_idx, f_point)\n",
|
||||
"optimizer.set_params(optimizer.params)\n",
|
||||
"v_def_optim_g_under_point = optimizer.solid.v_def.clone().detach() #bookkeeping"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"optimizer.reset_BFGS()\n",
|
||||
"optimizer.optimize(step_size_init=1e-4, max_l_iter=10, n_optim_steps=20)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Green (Optimum rest state under gravity) deploys to Black with the additional point load\n",
|
||||
"\n",
|
||||
"Blue (Optimized rest state) deploys to Yellow\n",
|
||||
"\n",
|
||||
"Red is the Target Shape\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"p = mp.plot(np.array(optimizer.solid.v_def) @ rot.T, tNP, shading=shadingOptions)\n",
|
||||
"# p.add_points(np.array(optimizer.solid.v_def)[pin_idx, :] @ rot.T, shading={\"point_color\":\"black\", \"point_size\": 0.2})\n",
|
||||
"p.add_edges(np.array(v_rest_optim_g) @ rot.T, beNP, shading={\"line_color\": \"green\"})\n",
|
||||
"p.add_edges(vNP @ rot.T, beNP, shading={\"line_color\": \"red\"})\n",
|
||||
"p.add_edges(np.array(v_def_optim_g_under_point) @ rot.T, beNP, shading={\"line_color\": \"black\"})\n",
|
||||
"p.add_edges(np.array(optimizer.solid.v_rest) @ rot.T, beNP, shading={\"line_color\": \"blue\"})\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Description\n",
|
||||
"\n",
|
||||
"This notebook intends to gather all the functionalities you'll have to implement for assignment 2.2.\n",
|
||||
"\n",
|
||||
"# Load libraries"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"import igl\n",
|
||||
"import meshplot as mp\n",
|
||||
"import time\n",
|
||||
"import torch\n",
|
||||
"\n",
|
||||
"import sys as _sys\n",
|
||||
"_sys.path.append(\"../src\")\n",
|
||||
"from elasticsolid import *\n",
|
||||
"from elasticenergy import *\n",
|
||||
"from vis_utils import *\n",
|
||||
"from matplotlib import gridspec\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"torch.set_default_dtype(torch.float64)\n",
|
||||
"\n",
|
||||
"shadingOptions = {\n",
|
||||
" \"flat\":True,\n",
|
||||
" \"wireframe\":False, \n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"rot = np.array(\n",
|
||||
" [[1, 0, 0 ],\n",
|
||||
" [0, 0, 1],\n",
|
||||
" [0, -1, 0 ]]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Load mesh\n",
|
||||
"\n",
|
||||
"Several meshes are available for you to play with under `data/`: `ball.obj`, `dinosaur.obj`, and `beam.obj`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"vNP, _, _, tNP, _, _ = igl.read_obj(\"../data/beam.obj\")\n",
|
||||
"aabb = np.max(vNP, axis=0) - np.min(vNP, axis=0)\n",
|
||||
"v = torch.tensor(vNP)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Linear/Non-Linear Elastic Solid\n",
|
||||
"\n",
|
||||
"## Instantiation\n",
|
||||
"\n",
|
||||
"We first specify the elasticity model to use for the elastic solid, as well as pinned vertices, and volumetric forces."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rho = 131 # [kg.m-3]\n",
|
||||
"young = 10e6 # [Pa] \n",
|
||||
"poisson = 0.2\n",
|
||||
"force_mass = torch.zeros(size = (3,))\n",
|
||||
"force_mass[2] = - rho * 9.81\n",
|
||||
"\n",
|
||||
"minX = torch.min(v[:, 0])\n",
|
||||
"pin_idx = torch.arange(v.shape[0])[v[:, 0] < minX + 0.2*aabb[0]]\n",
|
||||
"\n",
|
||||
"ee_lin = LinearElasticEnergy(young, poisson)\n",
|
||||
"ee_neo = NeoHookeanElasticEnergy(young, poisson)\n",
|
||||
"solid_lin = ElasticSolid(v, tNP, ee_lin, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n",
|
||||
"solid_neo = ElasticSolid(v, tNP, ee_neo, rho=rho, pin_idx=pin_idx, f_mass=force_mass)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Validate Elastic Energy Gradient (Elastic Forces) using Finite Differences on Elastic Energy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"solid_lin.update_def_shape(v)\n",
|
||||
"solid_neo.update_def_shape(v)\n",
|
||||
"\n",
|
||||
"fd_validation_elastic(solid_lin)\n",
|
||||
"fd_validation_elastic(solid_neo)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Validate External Energy Gradient (External Forces) using Finite Differences on External Energy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAbAAAAD8CAYAAAAWo/GJAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8/fFQqAAAACXBIWXMAAAsTAAALEwEAmpwYAABAtUlEQVR4nO29eZRc1X3v+/lWdfUodWtCCA0gYbAYhBlDAIchhjiAMR6uB4h5zw4ODnk2xr4vzzEJa3HXXY798PO6zyH2w2Gyc4MjrsEDQ2RsxzY4xkAAYYxAYAQISQhJCEnd6rmG3/vjnFNdXV1jd1d1H+n3WauWVLv2Pmfvrur69m/Yvy0zw3Ecx3HiRmKmJ+A4juM4k8EFzHEcx4klLmCO4zhOLHEBcxzHcWKJC5jjOI4TS1zAHMdxnFjSMtMTOJhYtGiRrVy5clJjBwYG6Orqmt4JzRAHyloOlHWAr2U2cqCsA6a2lqeeemq3mR1S6jUXsCaycuVKnnzyyUmNfeihhzjvvPOmd0IzxIGylgNlHeBrmY0cKOuAqa1F0mvlXnMXouM4jhNLXMAcx3GcWOIC5jiO48QSFzDHcRwnlriAOY7jOLHEBcxxHMeJJS5gU0TS+yXdKuleSe+e6fkU0z+SYfPugZmehuM4zrRTs4BJSkp6WtID9fap0H6tpA2SnpP0uYL2z4dtGyStldQuabWk3xY8+grH1IukOyTtkrShqP1CSS9K2iTpi9WuY2Y/MrOrgE8AH53sfBrFPz38Mu/9xq/JZHMzPRXHcZxppR4L7Fpg4yT7TGiXtAa4CjgdOBG4RNLRkpYBnwVOM7M1QBK4zMxeNLOTzOwk4FRgEPhh8Y0kLZY0t6jtqBJz+g5wYVG/JPBN4CLgOOBySceFr50g6YGix+KC4deHY2cVO/uG2T+c4VW3whzHOcCoScAkLQfeA9xWb58KY48FHjOzQTPLAA8DHwhfawE6JLUAncD2orHnAy+bWakd2ucC90pqD+9/FXBTcScz+xWwp6j5dGCTmb1iZqPAXcD7wv7PmtklRY9dCrgR+LGZrS/zs3mvpFt6e3tLvdxQ9g9nAHhue1/T7+04jtNIarXAvg58AajkhyrXp1z7BuAcSQsldQIXAyvM7HXga8AW4A2g18x+WjT2MmBtqUmY2d3Ag8Bdkj4GXAl8pMK8C1kGbC14vi1sq8Q1wAXAhyRdXWZO95vZp3p6emqcxvQxJmDNF0/HcZxGUlXAJF0C7DKzp+rtU2msmW0EbgR+RiA4zwAZSfMJrJ5VwFKgS9IVBddsBS4F7i43HzP7KjAM3Axcamb91dYZXb7U5SoNMLObzOxUM7vazL5V432axv7hNOAWmOM4Bx61WGDvBC6VtJnApfYuSXfW2KfiWDO73cxOMbNzCNx5LxFYM6+a2ZtmlgZ+AJxVcK+LgPVmtrPchCWdDawhiJHdUMMaI7YBKwqeL2ei+zJWFLoQzSpqseM4TqyoKmBmdp2ZLTezlQSuu1+Y2RW19Kk2NkqCkHQ48EECt+AW4AxJnZJEEO8qTAC5nDLuw/BaJwO3Elhxfw4skPSlausMeQI4WtKq0NK7DLivxrGzkr7hDK3JBL1DaV7fNzTT03Ecx5k2prQPTNI6SUuncInvS3oeuB/4tJntNbPHgXuA9cCz4RxvCe/XCfwJgVVWjk7gw2b2spnlgI8DE5I9JK0FHgVWS9om6ZNhMslngJ8QiOb3zOy5Kaxvxtk/nOakw+cB7kZ0HOfAoq7zwMzsIeChgucXV+tTqd3Mzi5znxso4fozs0FgYZU5PlL0PE1gkRX3u7zM+HXAukr3mEl27R+mPZWkuz1Vte9oJsdIJscfrJzPk5v38Nz2Pv70+CVNmKXjOE7j8UocMeMv/vlJrvv+szX1jRI4Fs9t58hD5vC8ZyI6jnMA4Scyx4y9g6O8tLOf4XSW9lSyYt8ogWNOWwvHL+3mP18t3vbmOI4TX9wCixnZrDGUzvLYK29V7RsJ2Nz2QMDe6B1mz8Boo6eY51e/f5P1W/Y27X6O4xxcuIDFjEwuSIX/+cZdVfvuHwlciHPbUxy/NNhE3cwNzV9et5Gbfv5S0+7nOM7BhQtYzMiGAvaLF3ZV3ddVbIFBczMR9w9n6BtKN+1+juMcXLiAxYx0Nsfc9hZe3zfEizv3V+wbCVh3e4p5na0sm9fRVAHrH8nk5+A4jjPduIDFjGzOOG91UAS/mhsxykKc2x7k6hy3tLtpLkQzo38kQ9+wW2CO4zQGF7CYkckZS3vaecfyHn6+sWw1LaAgCzESsMO6eXX3AMPpbMPnOZLJkc2ZW2CO4zQMF7CYkc0ZLUnxrmMW8/TWfbzVP1K27/7hNB2pJKlk8DYvm9+BGezqKz9muugfCYRrcDTrh2k6jtMQXMBihJmRyRnJRIILjj0UM3joxTfL9t8/nMm7DwEO62kHYEffcMPn2l9gebkV5jhOI3ABixFhAiItCXH80m4Wz23jly+Wj4MVC9iS7kDA3uhtfFHfyAKL5uE4jjPduIDFiHToiksmhCRWLepi1/7y7sC+4TRzC2omLgktsJ3NsMAKBMwTORzHaQQuYDEi2gPWkgjO3WxPJRmpkJBRbIHNbU/R1Zrkjd7GC9iAC5jjOA3GBSxGRFU4kqGAdaSSDFUUsPQ4AYPACmu2BeYuRMdxGoELWIyILLAoq7A9lWA4XT7Db/9whrlt449dWdLT3hQLzAXMcZxG4wIWIzK5sRgYQEdrZQusfyQz0QLr7mBHs12IXk7KcZwG4AIWI4pjYG0tybKbkjPZHIOj2XFJHABLetrYtX8kf61qbN83VLXmYin6R8bm5RaY4ziNwAUsRmSyRTGw1vICFrnwJsbAOsjmjN0VNkBHvL5viHfe+AsereHolgn3H84wp62FztZkvqSV4zjOdOICFiOiJI6WZJiF2JIknbWSlS4KK9EXcli4F6wWN+Ke/tFJV+4YGMnQ1Zakuz3lWYiO4zQEF7AYkc3HwIK3raM1+Hc4M1HA+obHzgIrJNoLVksiRzq832RqJ/aPZuhqa2Fue4u7EB3HaQguYDEissBSBfvAoLTAjB2lMjGNHmrbzBy5LCclYMMZ5rqAOY7TQFzApoik90u6VdK9kt7dyHsVx8AiARsaLS9gxRbYgs5WUknVZIFFWY+lLLxqBC7EFro73IXoOE5jqFnAJCUlPS3pgXr7VGi/VtIGSc9J+lxB++fDtg2S1kpql7Ra0m8LHn2FY+pF0h2SdknaUNR+oaQXJW2S9MVq1zGzH5nZVcAngI9Odj61kC2OgYUCNpIpJWDjzwKLSCTEod21bWaekgU2EiRxzG1PuQXmOE5DqMcCuxbYOMk+E9olrQGuAk4HTgQukXS0pGXAZ4HTzGwNkAQuM7MXzewkMzsJOBUYBH5YfCNJiyXNLWo7qsScvgNcWNQvCXwTuAg4Drhc0nHhaydIeqDosbhg+PXh2IaRKY6B5S2w2pM4ICjqW0tB37wFVmGzdDkiAetub/EsRMdxGkJNAiZpOfAe4LZ6+1QYeyzwmJkNmlkGeBj4QPhaC9AhqQXoBLYXjT0feNnMXisxlXOBeyW1h/e/CripuJOZ/QrYU9R8OrDJzF4xs1HgLuB9Yf9nzeySoscuBdwI/NjM1pf52bxX0i29vVM7DTmyiMZqIUZJHOUtsDmlBKynnZ01ZBamp2CBRS7Eue0p+obcAnMcZ/qp1QL7OvAFoNKf4uX6lGvfAJwjaaGkTuBiYIWZvQ58DdgCvAH0mtlPi8ZeBqwtNQkzuxt4ELhL0seAK4GPVJh3IcuArQXPt4VtlbgGuAD4kKSry8zpfjP7VE9PT43TKE22RC1EKB8Da21J0NaSnPBaZIFV26AcCWYpF2U1+kcyzGkPkjhGs7mmnALtOM7BRVUBk3QJsMvMnqq3T6WxZrYRuBH4GYHgPANkJM0nsHpWAUuBLklXFFyzFbgUuLvcfMzsq8AwcDNwqZn1V1tndPlSl6s0wMxuMrNTzexqM/tWjfeZFPksxGT1LMS+4cyEDMSIJT3tDKdzVS2jyboQRzJZ0lkLXIgdQRKJx8Ecx5luarHA3glcKmkzgUvtXZLurLFPxbFmdruZnWJm5xC4814isGZeNbM3zSwN/AA4q+BeFwHrzWxnuQlLOhtYQxAju6GGNUZsA1YUPF/ORPfljDFmgUXFfEMLrISABXUQUxPaoWAvWF/lONhkXYgDYRmprtZkXkQLMxE37cty3zOz5sfqOE5MqSpgZnadmS03s5UErrtfmNkVtfSpNjZKgpB0OPBBArfgFuAMSZ2SRBDvKkwAuZwy7sPwWicDtxJYcX8OLJD0pWrrDHkCOFrSqtDSuwy4r8axDSc60LI4BjZSwkIqdZRKxGE9tVXjiCp81Ctg/aG1Nac9lZ9DoQV2/8tpPrv2adb+55a6rus4jlPIlPaBSVonaekULvF9Sc8D9wOfNrO9ZvY4cA+wHng2nOMt4f06gT8hsMrK0Ql82MxeNrMc8HFgQrKHpLXAo8BqSdskfTJMJvkM8BMC0fyemT03hfVNK2VjYGU2MpcTsENrLCeVzkUWWH0uxKgO45ywlBSMr0i/Zzi47t/98Fke3PBGXdd2HMeJKP0NVwYzewh4qOD5xdX6VGo3s7PL3OcGSrj+zGwQWFhljo8UPU8TWGTF/S4vM34dsK7SPWaKTIkTmaFcJY40h8yZU/I6i+e2I8GOKnvB8hZYnUkcYwKWyrsxCy2wt4ZyfOjU5bzyZj+fXftbvnNlirPetqiueziO43gljhhRbIFVioFVssBaWxIs7GqraoFlJ2mBRWeBdbUlC1yI6fy/gxk4avEc7vjEH7ByUSf/x3fX+14xx3HqxgUsRmSKTmROJkRrMlFBwEoncUAQB6tmgUVJHCP1xsDyFthYFmKUxBGVsFo6r4N5na187cMnsm8wzf98tNSWPsdxnPK4gMWIbNGJzBAkchQncWRzVvI05kKW9LQ3LokLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"maxX = torch.max(v[:, 0])\n",
|
||||
"f_point_idx = torch.arange(v.shape[0])[v[:, 0] > maxX - 0.01*aabb[0]]\n",
|
||||
"\n",
|
||||
"f_point = torch.zeros(size=(f_point_idx.shape[0], 3))\n",
|
||||
"f_point[:, 2] = -5e3\n",
|
||||
"\n",
|
||||
"solid_lin.add_point_load(f_point_idx, f_point)\n",
|
||||
"solid_neo.add_point_load(f_point_idx, f_point)\n",
|
||||
"\n",
|
||||
"solid_lin.update_def_shape(v)\n",
|
||||
"solid_neo.update_def_shape(v)\n",
|
||||
"\n",
|
||||
"fd_validation_ext(solid_lin)\n",
|
||||
"fd_validation_ext(solid_neo)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 4.4.5 Point Force\n",
|
||||
"\n",
|
||||
"I tried adding a call to `make_external_energy` in the `add_point_load` function since a new force would also lead to a different energy. However inside `make_external_energy`, after many tries to add the energy corresponding to the point force, I gave up."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Validate Elastic Energy Force Differentials (Elastic Forces) using Finite Differences on Elastic Forces"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 432x288 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"needs_background": "light"
|
||||
},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"solid_lin.update_def_shape(v)\n",
|
||||
"solid_neo.update_def_shape(v)\n",
|
||||
"\n",
|
||||
"fd_validation_elastic_differentials(solid_lin)\n",
|
||||
"fd_validation_elastic_differentials(solid_neo)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import torch
|
||||
from utils import linear_solve
|
||||
|
||||
torch.set_default_dtype(torch.float64)
|
||||
|
||||
def compute_adjoint(solid ,dJdx_U):
|
||||
'''
|
||||
This assumes that S is at equilibrium when called
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid at equilibrium
|
||||
- dJdx_U : array of shape (3*#unpinned,)
|
||||
|
||||
Output:
|
||||
- adjoint : array of shape (3*#v,)
|
||||
'''
|
||||
y = torch.zeros_like(solid.v_rest)
|
||||
dx0s = torch.zeros_like(solid.v_rest)
|
||||
def LHS(dx):
|
||||
'''
|
||||
Should implement the Hessian-Vector product (taking into account pinning constraints) as described in the handout.
|
||||
'''
|
||||
dx0s[solid.free_idx] = dx.reshape(-1,3)
|
||||
df0s = - solid.compute_force_differentials(dx0s)
|
||||
return df0s[solid.free_idx].reshape(-1,)
|
||||
|
||||
RHS = dJdx_U.T.reshape(-1,)
|
||||
|
||||
y[solid.free_idx] = linear_solve(LHS, RHS).reshape(-1,3)
|
||||
|
||||
return y.reshape(-1,)
|
||||
@@ -0,0 +1,191 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
torch.set_default_dtype(torch.float64)
|
||||
|
||||
class ElasticEnergy:
|
||||
def __init__(self, young, poisson):
|
||||
'''
|
||||
Input:
|
||||
- young : Young's modulus [Pa]
|
||||
- poisson : Poisson ratio
|
||||
'''
|
||||
self.young = young
|
||||
self.poisson = poisson
|
||||
self.lbda = young * poisson / ((1 + poisson) * (1 - 2 * poisson))
|
||||
self.mu = young / (2 * (1 + poisson))
|
||||
|
||||
self.E = None
|
||||
self.dE = None
|
||||
self.psi = None
|
||||
self.P = None
|
||||
self.dP = None
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
'''
|
||||
This method computes the strain tensor (#t, 3, 3), and stores it in self.E
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
'''
|
||||
This method computes the differential of strain tensor (#t, 3, 3),
|
||||
and stores it in self.dE
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
- dJac : differential of the jacobian of the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
'''
|
||||
This method computes the energy density at each tetrahedron (#t,),
|
||||
and stores the result in self.psi
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
'''
|
||||
This method computes the stress tensor (#t, 3, 3), and stores it in self.P
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
'''
|
||||
This method computes the stress tensor (#t, 3, 3), and stores it in self.P
|
||||
|
||||
Input:
|
||||
- jac : jacobian of the deformation (#t, 3, 3)
|
||||
- dJac : differential of the jacobian of the deformation (#t, 3, 3)
|
||||
'''
|
||||
|
||||
print("Please specify the kind of elasticity model.")
|
||||
raise NotImplementedError
|
||||
|
||||
class LinearElasticEnergy(ElasticEnergy):
|
||||
def __init__(self, young, poisson):
|
||||
super().__init__(young, poisson)
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
|
||||
# First, update the strain tensor
|
||||
self.make_strain_tensor(jac)
|
||||
|
||||
# psi = mu*E:E + lbda/2*Tr(E)^2
|
||||
self.psi = (self.mu * torch.einsum('mij,mij->m', self.E, self.E) +
|
||||
self.lbda/2 * torch.einsum('mii->m', self.E) ** 2)
|
||||
pass
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
eye = torch.zeros((len(jac), 3, 3))
|
||||
for i in range(3):
|
||||
eye[:, i, i] = 1
|
||||
|
||||
# E = 1/2*(F + F^T) - I
|
||||
self.E = 0.5*(torch.swapaxes(jac, 1, 2) + jac) - eye
|
||||
pass
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
|
||||
# First, update the strain tensor
|
||||
self.make_strain_tensor(jac)
|
||||
|
||||
tr = torch.einsum('ijj->i', self.E)
|
||||
eye = torch.zeros((len(self.E), 3, 3))
|
||||
for i in range(3):
|
||||
eye[:, i, i] = tr
|
||||
|
||||
# P = 2*mu*E + lbda*tr(E)*I =
|
||||
self.P = 2 * self.mu * self.E + self.lbda * eye
|
||||
pass
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
# dE = 1/2*(dF + dF^T)
|
||||
self.dE = 0.5 * (dJac + torch.swapaxes(dJac, 1, 2))
|
||||
pass
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
|
||||
# First, update the differential of the strain tensor,
|
||||
# and the strain tensor
|
||||
self.make_strain_tensor(jac)
|
||||
self.make_differential_strain_tensor(jac, dJac)
|
||||
|
||||
# Diagonal matrix
|
||||
dtr = torch.einsum('ijj->i', self.dE)
|
||||
dI = torch.zeros((len(jac), 3, 3))
|
||||
for i in range(3):
|
||||
dI[:, i, i] = dtr
|
||||
|
||||
# dP = 2*mu*dE + lbda*tr(dE)*I
|
||||
self.dP = 2 * self.mu * self.dE + self.lbda * dI
|
||||
pass
|
||||
|
||||
|
||||
class NeoHookeanElasticEnergy(ElasticEnergy):
|
||||
def __init__(self, young, poisson):
|
||||
super().__init__(young, poisson)
|
||||
self.logJ = None
|
||||
self.Finv = None
|
||||
|
||||
def make_energy_density(self, jac):
|
||||
|
||||
# First, update the strain tensor
|
||||
self.make_strain_tensor(jac)
|
||||
|
||||
# J = det(F)
|
||||
# I1 = Tr(F^T.F)
|
||||
# psi = mu/2*(I1 - 3 - 2*log(J)) + lbda/2*log(J)^2
|
||||
logJ = torch.log(torch.linalg.det(jac))
|
||||
I1 = torch.einsum('mji,mji->m', jac, jac)
|
||||
self.psi = self.mu/2 * (I1 - 3 - 2*logJ) + self.lbda/2 * logJ**2
|
||||
pass
|
||||
|
||||
def make_strain_tensor(self, jac):
|
||||
pass
|
||||
|
||||
def make_piola_kirchhoff_stress_tensor(self, jac):
|
||||
self.logJ = torch.log(torch.linalg.det(jac))
|
||||
# First invert, then transpose
|
||||
self.Finv = torch.linalg.inv(jac)
|
||||
FinvT = torch.swapaxes(self.Finv, 1, 2)
|
||||
|
||||
# P = mu*(F - F^{-T}) + lbda*log(J)*F^{-T}
|
||||
self.P = (self.mu * (jac - FinvT) + self.lbda * torch.einsum('i,ijk->ijk', self.logJ, FinvT))
|
||||
pass
|
||||
|
||||
def make_differential_strain_tensor(self, jac, dJac):
|
||||
pass
|
||||
|
||||
def make_differential_piola_kirchhoff_stress_tensor(self, jac, dJac):
|
||||
|
||||
# To be reused below
|
||||
logJ = self.logJ.reshape(-1, 1, 1) # (#t, 1, 1) for shape broadcasting
|
||||
FinvT = torch.swapaxes(self.Finv, 1, 2)
|
||||
Fprod = torch.einsum("mij, mjk, mkl -> mil", FinvT, torch.swapaxes(dJac, 1, 2), FinvT)
|
||||
trFinvdF = torch.einsum("mij, mji -> m", self.Finv, dJac)
|
||||
|
||||
# dP = mu*dF + (mu-lbda*log(J))*F^{-T}.dF^T.F^{-T} + lbda*tr(F^{-1}.dF)*F^{-T}
|
||||
self.dP = (self.mu * dJac +
|
||||
(self.mu - self.lbda * logJ) * Fprod +
|
||||
self.lbda * torch.einsum("m, mij -> mij", trFinvdF, FinvT)
|
||||
)
|
||||
pass
|
||||
@@ -0,0 +1,458 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
import igl
|
||||
from utils import *
|
||||
|
||||
torch.set_default_dtype(torch.float64)
|
||||
|
||||
def to_numpy(tensor):
|
||||
return tensor.detach().clone().numpy()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
# ELASTIC SOLID CLASS (using PyTorch)
|
||||
# -----------------------------------------------------------------------------
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
class ElasticSolid(object):
|
||||
|
||||
def __init__(self, v_rest, t, ee, rho=1, pin_idx=[], f_mass=None):
|
||||
'''
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh (#v, 3)
|
||||
- t : indices of the element's vertices (#t, 4)
|
||||
- ee : elastic energy object that can be found in elasticenergy.py
|
||||
- rho : mass per unit volume [kg.m-3]
|
||||
- pin_idx : list or torch tensor of vertex indices to pin
|
||||
- f_mass : external force per unit mass (3,) [N.kg-1]
|
||||
'''
|
||||
|
||||
self.v_rest = v_rest
|
||||
self.v_def = v_rest
|
||||
self.t = t
|
||||
self.ee = ee
|
||||
self.rho = rho
|
||||
if not isinstance(pin_idx, torch.Tensor):
|
||||
pin_idx = torch.tensor(pin_idx)
|
||||
self.pin_idx = pin_idx
|
||||
self.f_mass = f_mass
|
||||
self.free_idx = None
|
||||
self.pin_mask = None
|
||||
|
||||
self.W0 = None
|
||||
self.Dm = None
|
||||
self.Bm = None
|
||||
self.rest_barycenters = None
|
||||
|
||||
self.W = None
|
||||
self.Ds = None
|
||||
self.F = None
|
||||
self.def_barycenters = None
|
||||
|
||||
self.energy_el = None
|
||||
self.energy_ext = None
|
||||
|
||||
self.f = None
|
||||
self.f_vol = None
|
||||
self.f_ext = None
|
||||
self.f_point = torch.zeros_like(v_rest)
|
||||
|
||||
self.dF = None
|
||||
|
||||
self.make_free_indices_and_pin_mask()
|
||||
self.update_rest_shape(self.v_rest)
|
||||
self.update_def_shape(self.v_def)
|
||||
|
||||
## Utils ##
|
||||
|
||||
def vertex_tet_sum(self, data):
|
||||
'''
|
||||
Distributes data specified at each tetrahedron to the neighboring vertices.
|
||||
All neighboring vertices will receive the value indicated at the corresponding tet position in data.
|
||||
|
||||
Input:
|
||||
- data : torch array of shape (#t,)
|
||||
|
||||
Output:
|
||||
- data_sum : torch array of shape (#v,), containing the summed data
|
||||
'''
|
||||
i = self.t.T.flatten() # (4*#t,)
|
||||
j = torch.arange(self.t.shape[0]) # (#t,)
|
||||
j = torch.tile(j, (4,)) # (4*#t,)
|
||||
|
||||
# Has shape (#v, #t), a bit less efficient than using sparse matrices
|
||||
m = torch.zeros(size=(self.v_rest.shape[0], self.t.shape[0]), dtype=torch.float64)
|
||||
m[i, j] = data
|
||||
|
||||
return torch.sum(m, dim=1)
|
||||
|
||||
## Precomputation ##
|
||||
|
||||
def make_free_indices_and_pin_mask(self):
|
||||
'''
|
||||
Should list all the free indices and the pin mask.
|
||||
|
||||
Updated attributes:
|
||||
- free_index : torch tensor of shape (#free_vertices,) containing the list of unpinned vertices
|
||||
- pin_mask : torch tensor of shape (#v, 1) containing 1 at free vertex indices and 0 at pinned vertex indices
|
||||
'''
|
||||
|
||||
vi = torch.arange(self.v_rest.shape[0])
|
||||
pin_filter = ~torch.isin(vi, self.pin_idx)
|
||||
self.free_idx = vi[pin_filter]
|
||||
|
||||
self.pin_mask = torch.tensor([idx not in self.pin_idx
|
||||
for idx in range(self.v_rest.shape[0])]).reshape(-1, 1)
|
||||
|
||||
## Methods related to rest quantities ##
|
||||
|
||||
def make_rest_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the undeformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- rest_barycenters : torch tensor of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
|
||||
self.rest_barycenters = torch.einsum('ijk -> ik', self.v_rest[self.t]) / 4
|
||||
|
||||
def make_rest_shape_matrices(self):
|
||||
'''
|
||||
Construct Ds that has shape (#t, 3, 3), and its inverse Bm
|
||||
|
||||
Updated attributes:
|
||||
- Dm : torch tensor of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
- Bm : torch tensor of shape (#t, 3, 3) containing the inverse shape matrix of each tet
|
||||
'''
|
||||
|
||||
e1 = (self.v_rest[self.t[:, 0]] - self.v_rest[self.t[:, 3]])
|
||||
e2 = (self.v_rest[self.t[:, 1]] - self.v_rest[self.t[:, 3]])
|
||||
e3 = (self.v_rest[self.t[:, 2]] - self.v_rest[self.t[:, 3]])
|
||||
Ds = torch.stack((e1, e2, e3), dim=2)
|
||||
self.Dm = Ds
|
||||
self.Bm = torch.linalg.inv(self.Dm)
|
||||
|
||||
def update_rest_shape(self, v_rest):
|
||||
'''
|
||||
Updates the vertex position, the shape matrices Dm and Bm, the volumes W0,
|
||||
and the mass matrix at rest
|
||||
|
||||
Input:
|
||||
- v_rest : position of the vertices of the mesh at rest state (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_rest : torch tensor of shape (#v, 3) containing the position of each vertex at rest
|
||||
- W0 : torch tensor of shape (#t,) containing the signed volume of each tet
|
||||
'''
|
||||
|
||||
self.v_rest = v_rest
|
||||
self.make_rest_barycenters()
|
||||
self.make_rest_shape_matrices()
|
||||
self.W0 = - torch.linalg.det(self.Dm) / 6
|
||||
self.make_volumetric_and_external_forces()
|
||||
self.update_def_shape(self.v_def)
|
||||
|
||||
## Methods related to deformed quantities ##
|
||||
|
||||
def make_def_barycenters(self):
|
||||
'''
|
||||
Construct the barycenters of the deformed configuration
|
||||
|
||||
Updated attributes:
|
||||
- def_barycenters : torch tensor of shape (#t, 3) containing the position of each tet's barycenter
|
||||
'''
|
||||
|
||||
self.def_barycenters = torch.einsum('ijk -> ik', self.v_def[self.t]) / 4
|
||||
|
||||
def make_def_shape_matrices(self):
|
||||
'''
|
||||
Construct Ds that has shape (#t, 3, 3)
|
||||
|
||||
Updated attributes:
|
||||
- Ds : torch tensor of shape (#t, 3, 3) containing the shape matrix of each tet
|
||||
'''
|
||||
|
||||
e1 = (self.v_def[self.t[:, 0]] - self.v_def[self.t[:, 3]])
|
||||
e2 = (self.v_def[self.t[:, 1]] - self.v_def[self.t[:, 3]])
|
||||
e3 = (self.v_def[self.t[:, 2]] - self.v_def[self.t[:, 3]])
|
||||
Ds = torch.stack((e1, e2, e3), dim=2)
|
||||
self.Ds = Ds
|
||||
|
||||
def make_jacobians(self):
|
||||
'''
|
||||
Compute the current Jacobian of the deformation
|
||||
|
||||
Updated attributes:
|
||||
- F : torch tensor of shape (#t, 3, 3) containing Jacobian of the deformation in each tet
|
||||
'''
|
||||
|
||||
self.F = torch.einsum('lij,ljk->lik', self.Ds, self.Bm)
|
||||
|
||||
def update_def_shape(self, v_def):
|
||||
'''
|
||||
Updates the vertex position, the Jacobian of the deformation, and the
|
||||
resulting elastic forces.
|
||||
|
||||
Input:
|
||||
- v_def : position of the vertices of the mesh (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- v_def : torch tensor of shape (#v, 3) containing the position of each vertex after deforming the solid
|
||||
- W : torch tensor of shape (#t,) containing the signed volume of each tet
|
||||
'''
|
||||
|
||||
# Can only change the unpinned ones
|
||||
self.v_def = (~self.pin_mask) * self.v_rest + self.pin_mask * v_def
|
||||
self.make_def_barycenters()
|
||||
self.make_def_shape_matrices()
|
||||
self.make_jacobians()
|
||||
self.W = - torch.linalg.det(self.Ds) / 6
|
||||
self.make_elastic_forces()
|
||||
self.make_elastic_energy()
|
||||
self.make_external_energy()
|
||||
|
||||
def displace(self, v_disp):
|
||||
'''
|
||||
Displace the whole mesh so that v_def += v_disp
|
||||
|
||||
Input:
|
||||
- v_disp : displacement of the vertices of the mesh (#v, 3)
|
||||
'''
|
||||
|
||||
self.update_def_shape(self.v_def + v_disp)
|
||||
|
||||
## Energies ##
|
||||
|
||||
def make_elastic_energy(self):
|
||||
'''
|
||||
This updates the elastic energy
|
||||
|
||||
Updated attributes:
|
||||
- energy_el : elastic energy of the system [J]
|
||||
'''
|
||||
self.ee.make_strain_tensor(self.F)
|
||||
self.ee.make_energy_density(self.F)
|
||||
self.energy_el = torch.sum(self.W0 * self.ee.psi)
|
||||
|
||||
def make_external_energy(self):
|
||||
'''
|
||||
This computes the external energy potential
|
||||
|
||||
Updated attributes:
|
||||
- energy_ext : postential energy due to external forces [J]
|
||||
'''
|
||||
self.energy_ext = - torch.einsum('i, ij, ij->', self.W0, self.f_vol, self.def_barycenters - self.rest_barycenters)
|
||||
# TODO: ADD F_POINT ENERGY
|
||||
|
||||
## Forces ##
|
||||
|
||||
def make_elastic_forces(self):
|
||||
'''
|
||||
This method updates the elastic forces stored in self.f (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- f : elastic forces per vertex (#v, 3)
|
||||
- ee : elastic energy, some attributes should be updated
|
||||
'''
|
||||
|
||||
# First update strain/stress tensor, stored in self.ee
|
||||
self.ee.make_strain_tensor(self.F)
|
||||
self.ee.make_piola_kirchhoff_stress_tensor(self.F)
|
||||
|
||||
# H[el] = - W0[el]*P.Bm[el]^T
|
||||
H = torch.einsum('lij,ljk->lik', self.ee.P, torch.swapaxes(self.Bm, 1, 2))
|
||||
H = - torch.einsum('i,ijk->ijk', self.W0, H)
|
||||
|
||||
# Extract forces from H of shape (#t, 3, 3)
|
||||
# We look at each component separately, then stack them in a vector of shape (4*#t,)
|
||||
# Then we distribute the contributions to each vertex
|
||||
fx = self.vertex_tet_sum(torch.hstack((H[:, 0, 0], H[:, 0, 1], H[:, 0, 2],
|
||||
-H[:, 0, 0] - H[:, 0, 1] - H[:, 0, 2])))
|
||||
fy = self.vertex_tet_sum(torch.hstack((H[:, 1, 0], H[:, 1, 1], H[:, 1, 2],
|
||||
-H[:, 1, 0] - H[:, 1, 1] - H[:, 1, 2])))
|
||||
fz = self.vertex_tet_sum(torch.hstack((H[:, 2, 0], H[:, 2, 1], H[:, 2, 2],
|
||||
-H[:, 2, 0] - H[:, 2, 1] - H[:, 2, 2])))
|
||||
|
||||
# We stack them in a tensor of shape (#v, 3)
|
||||
self.f = torch.column_stack((fx, fy, fz))
|
||||
|
||||
def add_point_load(self, v_idx, f_point):
|
||||
'''
|
||||
Input:
|
||||
- v_idx : tensor of size (n_idx,) containing the list of vertex ids
|
||||
- f_point : tensor of size (n_idx, 3) containing force to add at each vertex
|
||||
|
||||
Updated attributes:
|
||||
- f_point : tensor of size (#v, 3)
|
||||
'''
|
||||
self.f_point[v_idx] += f_point
|
||||
self.make_volumetric_and_external_forces()
|
||||
self.make_external_energy()
|
||||
|
||||
def make_volumetric_and_external_forces(self):
|
||||
'''
|
||||
Convert force per unit mass to volumetric forces, then distribute
|
||||
the forces to the vertices of the mesh.
|
||||
|
||||
Updated attributes:
|
||||
- f_vol : torch tensor of shape (#t, 3) external force per unit volume acting on the tets
|
||||
- f_ext : torch tensor of shape (#v, 3) external force acting on the vertices
|
||||
'''
|
||||
self.f_vol = torch.tile((self.rho * self.f_mass), (self.t.shape[0], 1)) # (#t, 3)
|
||||
int_f_vol = torch.einsum('i, ij -> ij', self.W0, self.f_vol)
|
||||
|
||||
# from (#t,) to (4*#t,)
|
||||
j = torch.arange(len(self.t))
|
||||
j = torch.tile(j, (4,))
|
||||
int_f_vol_tiled = int_f_vol[j]
|
||||
|
||||
f_ext_x = self.vertex_tet_sum(int_f_vol_tiled[:, 0])
|
||||
f_ext_y = self.vertex_tet_sum(int_f_vol_tiled[:, 1])
|
||||
f_ext_z = self.vertex_tet_sum(int_f_vol_tiled[:, 2])
|
||||
self.f_ext = torch.stack((f_ext_x, f_ext_y, f_ext_z), dim=1) / 4 + self.f_point
|
||||
|
||||
|
||||
## Force Differentials
|
||||
|
||||
def compute_force_differentials(self, v_disp):
|
||||
'''
|
||||
This computes the differential of the force given a displacement dx,
|
||||
where df = df/dx|x . dx = - K(x).dx. The matrix vector product K(x)w
|
||||
is then given by the call self.compute_force_differentials(-w).
|
||||
|
||||
Input:
|
||||
- v_disp : displacement of the vertices of the mesh (#v, 3)
|
||||
|
||||
Output:
|
||||
- df : force differentials at the vertices of the mesh (#v, 3)
|
||||
|
||||
Updated attributes:
|
||||
- ee : elastic energy, some attributes should be updated
|
||||
'''
|
||||
|
||||
# Compute the displacement differentials
|
||||
d1 = (v_disp[self.t[:, 0]] - v_disp[self.t[:, 3]]).reshape(-1, 3, 1)
|
||||
d2 = (v_disp[self.t[:, 1]] - v_disp[self.t[:, 3]]).reshape(-1, 3, 1)
|
||||
d3 = (v_disp[self.t[:, 2]] - v_disp[self.t[:, 3]]).reshape(-1, 3, 1)
|
||||
dDs = torch.cat((d1, d2, d3), dim=2)
|
||||
|
||||
# Differential of the Jacobian
|
||||
dF = torch.einsum('lij,ljk->lik', dDs, self.Bm)
|
||||
|
||||
# Differential of the stress tensor (uses the current stress tensor)
|
||||
self.ee.make_differential_strain_tensor(self.F, dF)
|
||||
self.ee.make_differential_piola_kirchhoff_stress_tensor(self.F, dF)
|
||||
|
||||
# Differential of the forces
|
||||
dH = torch.einsum('lij,ljk->lik', self.ee.dP, torch.swapaxes(self.Bm, 1, 2))
|
||||
dH = - torch.einsum('i,ijk->ijk', self.W0, dH)
|
||||
|
||||
# Same as for the elastic forces
|
||||
dfx = self.vertex_tet_sum(torch.hstack((dH[:, 0, 0], dH[:, 0, 1], dH[:, 0, 2],
|
||||
-dH[:, 0, 0] - dH[:, 0, 1] - dH[:, 0, 2])))
|
||||
dfy = self.vertex_tet_sum(torch.hstack((dH[:, 1, 0], dH[:, 1, 1], dH[:, 1, 2],
|
||||
-dH[:, 1, 0] - dH[:, 1, 1] - dH[:, 1, 2])))
|
||||
dfz = self.vertex_tet_sum(torch.hstack((dH[:, 2, 0], dH[:, 2, 1], dH[:, 2, 2],
|
||||
-dH[:, 2, 0] - dH[:, 2, 1] - dH[:, 2, 2])))
|
||||
|
||||
# We stack them in a tensor of shape (#v, 3)
|
||||
return torch.column_stack((dfx, dfy, dfz))
|
||||
|
||||
def equilibrium_step(self, verbose=False):
|
||||
'''
|
||||
This function displaces the whole solid to the next deformed configuration
|
||||
using a Newton-CG step.
|
||||
|
||||
Input:
|
||||
- verbose : whether or not to display quantities
|
||||
|
||||
Updated attributes:
|
||||
- LHS : The hessian vector product
|
||||
- RHS : Right hand side for the conjugate gradient linear solve
|
||||
Other than them, only attributes updated by displace(self, v_disp) should be changed
|
||||
'''
|
||||
|
||||
dx0s = torch.zeros_like(self.v_rest)
|
||||
|
||||
# Define LHS
|
||||
def LHS(dx):
|
||||
'''
|
||||
Should implement the Hessian-Vector Product L(dx), and take care of pinning constraints
|
||||
as described in the handout.
|
||||
'''
|
||||
dx0s[self.free_idx] = dx.reshape(-1,3)
|
||||
df0s = - self.compute_force_differentials(dx0s)
|
||||
return df0s[self.free_idx, :].reshape(-1,)
|
||||
self.LHS = LHS # Save to class for testing
|
||||
|
||||
# Define RHS
|
||||
ft = self.f + self.f_ext
|
||||
RHS = ft[self.free_idx, :].reshape(-1,)
|
||||
self.RHS = RHS # Save to class for testing
|
||||
|
||||
dx = conjugate_gradient(LHS, RHS)
|
||||
dx0s[self.free_idx] = dx.reshape(-1, 3)
|
||||
|
||||
# Run line search on the direction
|
||||
step_size = 2
|
||||
ft_free = RHS
|
||||
g_old = torch.linalg.norm(ft_free)
|
||||
max_l_iter = 20
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size *= 0.5
|
||||
dx_search = dx0s * step_size
|
||||
energy_tot_prev = self.energy_el + self.energy_ext
|
||||
self.displace(dx_search)
|
||||
ft_new = (self.f_ext + self.f)[self.free_idx].reshape(-1,)
|
||||
g = torch.linalg.norm(ft_new)
|
||||
|
||||
energy_tot_tmp = self.energy_el + self.energy_ext
|
||||
armijo = energy_tot_tmp < energy_tot_prev - 1e-4*step_size*torch.sum(dx.reshape(-1,)*ft_free)
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
if verbose:
|
||||
print("Energy: " + str(energy_tot_tmp) + " Force residual norm: " + str(g) + " Line search Iters: " + str(l_iter))
|
||||
break
|
||||
else:
|
||||
self.displace(-dx_search)
|
||||
|
||||
def find_equilibrium(self, n_steps=100, thresh=1., verbose=False):
|
||||
'''
|
||||
Input:
|
||||
- n_steps : maximum number of optimization steps
|
||||
- thresh : threshold on the force value [N]
|
||||
'''
|
||||
for i in range(n_steps):
|
||||
# Take a Newton-CG step
|
||||
self.equilibrium_step(verbose=verbose)
|
||||
assert not torch.isnan(self.energy_el)
|
||||
|
||||
# Measure the force residuals
|
||||
residuals_tmp = torch.linalg.norm((self.f + self.f_ext)[self.free_idx, :])
|
||||
|
||||
if residuals_tmp < thresh:
|
||||
break
|
||||
if verbose: print("Final residuals (equilibrium): {:.2e}".format(to_numpy(residuals_tmp)))
|
||||
|
||||
def vertex_tet_sum(v, t, data):
|
||||
'''
|
||||
Distributes data specified at each tetrahedron to the neighboring vertices.
|
||||
All neighboring vertices will receive the value indicated at the corresponding tet position in data.
|
||||
|
||||
Input:
|
||||
- num_vert : number of vertices
|
||||
- t : connectivity of the volumetric mesh (#t, 4)
|
||||
- data : torch array of shape (#t,)
|
||||
|
||||
Output:
|
||||
- data_sum : torch array of shape (#v,), containing the summed data
|
||||
'''
|
||||
i = t.T.flatten() # (4*#t,)
|
||||
j = torch.arange(t.shape[0]) # (#t,)
|
||||
j = torch.tile(j, (4,)) # (4*#t,)
|
||||
|
||||
# Has shape (#v, #t), a bit less efficient than using sparse matrices
|
||||
m = torch.zeros(size=(v.shape[0], t.shape[0]), dtype=torch.float64)
|
||||
m[i, j] = data
|
||||
|
||||
return torch.sum(m, dim=1)
|
||||
@@ -0,0 +1,88 @@
|
||||
import torch
|
||||
import igl
|
||||
import numpy as np
|
||||
|
||||
torch.set_default_dtype(torch.float64)
|
||||
|
||||
def to_numpy(tensor):
|
||||
return tensor.detach().clone().numpy()
|
||||
|
||||
class HarmonicInterpolator:
|
||||
'''
|
||||
Provides a way to interpolate boundary vertices
|
||||
|
||||
Attributes:
|
||||
- lii : block of the Laplacian matrix associated to
|
||||
interior vertices (#iv, #iv)
|
||||
- lib : block of the Laplacian matrix associated to
|
||||
interior/boundary vertices (#iv, #v - #iv)
|
||||
- lii_inv : inverse of lii (#iv, #iv)
|
||||
'''
|
||||
|
||||
def __init__(self, v, t, iv):
|
||||
'''
|
||||
Input:
|
||||
- v : tensor of shape (#v, 3)
|
||||
- t : tensor of shape (#t, 4)
|
||||
- iv : np array containing interior vertices (#iv,)
|
||||
'''
|
||||
self.lii = None
|
||||
self.lib = None
|
||||
self.lii_inv = None
|
||||
|
||||
self.iv = None
|
||||
self.bv = None
|
||||
|
||||
self.update_interpolator(v, t, iv)
|
||||
|
||||
def update_interpolator(self, v, t, iv):
|
||||
'''
|
||||
Input:
|
||||
- v : tensor of shape (#v, 3)
|
||||
- t : tensor of shape (#t, 4)
|
||||
- iv : np array containing interior vertices (#iv,)
|
||||
'''
|
||||
|
||||
vNP = to_numpy(v)
|
||||
tNP = to_numpy(t)
|
||||
|
||||
self.iv = iv
|
||||
v_idx = np.arange(v.shape[0])
|
||||
self.bv = v_idx[np.invert(np.in1d(v_idx, iv))]
|
||||
|
||||
l = igl.cotmatrix(vNP, tNP).todense()
|
||||
self.lii = torch.tensor(l[iv[:, np.newaxis], self.iv])
|
||||
self.lib = torch.tensor(l[iv[:, np.newaxis], self.bv])
|
||||
self.lii_inv = torch.linalg.inv(self.lii)
|
||||
|
||||
def interpolate(self, v_surf):
|
||||
'''
|
||||
Input:
|
||||
- v_surf : tensor of shape (#v - #iv, 3) for which the interior vertices
|
||||
should be interpolated
|
||||
|
||||
Output:
|
||||
- v_inter : tensor of shape (#v, 3) for which the interior vertices
|
||||
have been interpolated from vertices of v_surf
|
||||
'''
|
||||
n_v = self.bv.shape[0] + self.iv.shape[0]
|
||||
v_inter = torch.zeros(size=(n_v, 3))
|
||||
v_inter[self.bv, :] = v_surf
|
||||
v_inter[self.iv, :] = - self.lii_inv @ self.lib @ v_surf
|
||||
return v_inter
|
||||
|
||||
def interpolate_fill(self, v_vol):
|
||||
'''
|
||||
Input:
|
||||
- v_vol : tensor of shape (#v, 3) for which the interior vertices
|
||||
should be interpolated
|
||||
|
||||
Output:
|
||||
- v_inter : tensor of shape (#v, 3) for which the interior vertices
|
||||
have been interpolated from vertices of v_surf
|
||||
'''
|
||||
n_v = self.bv.shape[0] + self.iv.shape[0]
|
||||
assert n_v == v_vol.shape[0]
|
||||
v_inter = v_vol
|
||||
v_inter[self.iv, :] = - self.lii_inv @ self.lib @ v_vol[self.bv, :]
|
||||
return v_inter
|
||||
@@ -0,0 +1,119 @@
|
||||
from elasticenergy import *
|
||||
from elasticsolid import *
|
||||
import torch
|
||||
|
||||
class ObjectiveBV:
|
||||
def __init__(self, vt_surf, bv):
|
||||
self.vt_surf, self.bv= vt_surf, bv
|
||||
|
||||
def obj(self, v):
|
||||
return objective_target_BV(v, self.vt_surf, self.bv)
|
||||
|
||||
def grad(self, v):
|
||||
return grad_objective_target_BV(v, self.vt_surf, self.bv)
|
||||
|
||||
class ObjectiveReg:
|
||||
def __init__(self, params_init, params_idx, harm_int, weight_reg=0, force_scale=1e7, length_scale=1.):
|
||||
self.params_init, self.params_idx, self.harm_int = params_init, params_idx, harm_int
|
||||
self.weight_reg, self.force_scale, self.length_scale = weight_reg, force_scale, length_scale
|
||||
|
||||
def obj(self, solid, params_tmp):
|
||||
if self.weight_reg == 0: return 0
|
||||
return self.length_scale * self.weight_reg / self.force_scale *regularization_neo_hookean(self.params_init, solid, params_tmp, self.params_idx, self.harm_int)
|
||||
|
||||
def grad(self, solid, params_tmp):
|
||||
if self.weight_reg == 0: return torch.zeros_like(self.params_init)
|
||||
return self.length_scale * self.weight_reg / self.force_scale *regularization_grad_neo_hookean(self.params_init, solid, params_tmp, self.params_idx, self.harm_int)
|
||||
|
||||
|
||||
def objective_target_BV(v, vt, bv):
|
||||
'''
|
||||
Input:
|
||||
- v : array of shape (#v, 3), containing the current vertices position
|
||||
- vt : array of shape (#bv, 3), containing the target surface
|
||||
- bv : boundary vertices index (#bv,)
|
||||
|
||||
Output:
|
||||
- objective : single scalar measuring the deviation from the target shape
|
||||
'''
|
||||
vc = v[bv]
|
||||
J = 0.5 * torch.norm(vc-vt)**2
|
||||
return J
|
||||
|
||||
def grad_objective_target_BV(v, vt, bv):
|
||||
'''
|
||||
Input:
|
||||
- v : array of shape (#v, 3), containing the current vertices position
|
||||
- vt : array of shape (#bv, 3), containing the target surface
|
||||
- bv : boundary vertices (#bv,)
|
||||
|
||||
Output:
|
||||
- gradient : array of shape (#v, 3)
|
||||
'''
|
||||
vc = v[bv]
|
||||
dJ = vc - vt
|
||||
res = torch.zeros(v.shape)
|
||||
res[bv] = dJ
|
||||
return res
|
||||
|
||||
def regularization_neo_hookean(params_prev, solid, params, params_idx, harm_int):
|
||||
'''
|
||||
Input:
|
||||
- params_prev : array of shape (3*#params,) containing the previous shape
|
||||
- solid : an elastic solid to copy
|
||||
- params : array of shape (3*#params,) containing the new shape parameters
|
||||
- params_idx : parameters index in the vertex list. Has shape (#params,)
|
||||
- harm_int : an harmonic interpolator
|
||||
|
||||
Output:
|
||||
- energy : the neo hookean energy
|
||||
'''
|
||||
|
||||
v_prev = solid.v_rest.detach()
|
||||
v_prev[params_idx, :] = params_prev.reshape(-1, 3)
|
||||
v_prev = harm_int.interpolate_fill(v_prev)
|
||||
|
||||
f_mass = torch.zeros(size=(3,))
|
||||
|
||||
ee_tmp = NeoHookeanElasticEnergy(solid.ee.young, solid.ee.poisson)
|
||||
solid_virtual = ElasticSolid(v_prev, solid.t, ee_tmp, rho=solid.rho,
|
||||
pin_idx=solid.pin_idx, f_mass=f_mass)
|
||||
|
||||
v_new = solid_virtual.v_rest.detach()
|
||||
v_new[params_idx, :] = params.reshape(-1, 3)
|
||||
v_new = harm_int.interpolate_fill(v_new)
|
||||
solid_virtual.update_def_shape(v_new)
|
||||
|
||||
solid_virtual.make_elastic_energy()
|
||||
|
||||
return solid_virtual.energy_el
|
||||
|
||||
def regularization_grad_neo_hookean(params_prev, solid, params, params_idx, harm_int):
|
||||
'''
|
||||
Input:
|
||||
- params_prev : array of shape (3*#params,) containing the previous shape
|
||||
- solid : an elastic solid to copy
|
||||
- params : array of shape (3*#params,) containing the new shape parameters
|
||||
- params_idx : parameters index in the vertex list. Has shape (#params,)
|
||||
- harm_int : an harmonic interpolator
|
||||
|
||||
Output:
|
||||
- grad_reg : array of shape (3*#params,), the regularization gradient
|
||||
'''
|
||||
|
||||
v_prev = solid.v_rest.detach()
|
||||
v_prev[params_idx, :] = params_prev.reshape(-1, 3)
|
||||
v_prev = harm_int.interpolate_fill(v_prev)
|
||||
|
||||
ee_tmp = NeoHookeanElasticEnergy(solid.ee.young, solid.ee.poisson)
|
||||
solid_virtual = ElasticSolid(v_prev, solid.t, ee_tmp, rho=solid.rho,
|
||||
pin_idx=solid.pin_idx, f_mass=solid.f_mass)
|
||||
|
||||
v_new = solid_virtual.v_rest.detach()
|
||||
v_new[params_idx, :] = params.reshape(-1, 3)
|
||||
v_new = harm_int.interpolate_fill(v_new)
|
||||
solid_virtual.update_def_shape(v_new)
|
||||
|
||||
# Negative of the elastic forces: gradient of the energy
|
||||
grad_reg = - solid_virtual.f[params_idx].reshape(-1,)
|
||||
return grad_reg
|
||||
@@ -0,0 +1,310 @@
|
||||
import torch
|
||||
|
||||
from elasticsolid import *
|
||||
from objectives import *
|
||||
from harmonic_interpolator import *
|
||||
from adjoint_sensitivity import *
|
||||
|
||||
from IPython import display
|
||||
import time
|
||||
|
||||
from vis_utils import plot_torch_solid
|
||||
from utils import *
|
||||
|
||||
torch.set_default_dtype(torch.float64)
|
||||
|
||||
|
||||
class ShapeOptimizer():
|
||||
def __init__(self, solid, vt_surf, weight_reg=0.):
|
||||
|
||||
|
||||
# Elastic Solid with the initial rest vertices stored
|
||||
self.solid = solid
|
||||
|
||||
# Mesh info of solid
|
||||
bvNP, ivNP = get_boundary_and_interior(solid.v_rest.shape[0], to_numpy(solid.t))
|
||||
self.bvNP, self.ivNP = bvNP, ivNP
|
||||
self.beNP = igl.edges(igl.boundary_facets(to_numpy(solid.t)))
|
||||
|
||||
# Initialize Laplacian/Harmonic Interpolator
|
||||
v_init_rest = solid.v_rest.clone().detach()
|
||||
self.harm_int = HarmonicInterpolator(v_init_rest, solid.t, ivNP)
|
||||
|
||||
# Initialize interior vertices with harmonic interpolation
|
||||
self.v_init_rest = self.harm_int.interpolate(v_init_rest[bvNP])
|
||||
solid.update_rest_shape(self.v_init_rest)
|
||||
|
||||
# Define optimization params and their indices
|
||||
self.params_idx = torch.tensor(np.intersect1d(to_numpy(solid.free_idx), bvNP))
|
||||
params_init = v_init_rest[self.params_idx].reshape(-1,)
|
||||
self.params, self.params_prev = params_init.clone(), params_init.clone() # At time step t, t-1
|
||||
|
||||
# Target surface and Objectives
|
||||
self.vt_surf = vt_surf
|
||||
self.tgt_fit = ObjectiveBV(vt_surf, bvNP)
|
||||
self.neo_reg = ObjectiveReg(params_init.clone().detach(), self.params_idx, self.harm_int, weight_reg = weight_reg)
|
||||
|
||||
# Compute equilibrium deformation
|
||||
self.solid.find_equilibrium()
|
||||
obj_init = self.tgt_fit.obj(solid.v_def.clone().detach())
|
||||
print("Initial objective: {:.4e}\n".format(obj_init))
|
||||
|
||||
# Initialize grad
|
||||
self.grad = torch.zeros(size=(3 * self.params_idx.shape[0],))
|
||||
|
||||
# BFGS book-keeping
|
||||
self.invB = torch.eye(3 * self.params_idx.shape[0])
|
||||
self.grad_prev = torch.zeros(size=(3 * self.params_idx.shape[0],))
|
||||
|
||||
def compute_gradient(self):
|
||||
'''
|
||||
Computes the full gradient including the forward simulation and regularization.
|
||||
|
||||
Updated attributes:
|
||||
- grad : torch.tensor of shape (#params,)
|
||||
'''
|
||||
# dJ/dx from Target Fitting
|
||||
dJ_dx = self.tgt_fit.grad(self.solid.v_def.clone().detach())[self.solid.free_idx]
|
||||
|
||||
self.grad = gradient_helper_autograd(self.solid, dJ_dx, self.params, self.params_idx, self.harm_int)
|
||||
|
||||
# Add regularization gradient
|
||||
self.grad = self.grad + self.neo_reg.grad(self.solid, self.params)
|
||||
return self.grad
|
||||
|
||||
def update_BFGS(self):
|
||||
'''
|
||||
Update BFGS hessian inverse approximation
|
||||
|
||||
Updated attributes:
|
||||
- invB : torch.tensor of shape (#params, #params)
|
||||
'''
|
||||
sk = self.params - self.params_prev
|
||||
yk = self.grad - self.grad_prev
|
||||
self.invB = compute_inverse_approximate_hessian_matrix(sk.reshape(-1, 1), yk.reshape(-1, 1), self.invB)
|
||||
|
||||
def reset_BFGS(self):
|
||||
'''
|
||||
Reset BFGS hessian inverse approximation to Identity
|
||||
|
||||
Updated attributes:
|
||||
- invB : torch.tensor of shape (#params, #params)
|
||||
'''
|
||||
self.invB = torch.eye(3 * self.params_idx.shape[0])
|
||||
|
||||
def set_params(self, params_in, verbose=False):
|
||||
'''
|
||||
Set optimization params to the input params_in
|
||||
|
||||
Input:
|
||||
- params_in : Input params to set the solid to, torch.tensor of shape (#params,)
|
||||
- verbose : Boolean specifying the verbosity of the equilibrium solve
|
||||
|
||||
Updated attributes:
|
||||
- solid : Elastic solid, specifically, the rest shape and consequently the equilibrium deformation
|
||||
'''
|
||||
# From the input params_in, interpolate all the rest vertices using harm_int
|
||||
v_search = self.solid.v_rest.clone()
|
||||
v_search[self.params_idx, :] = params_in.reshape(-1, 3)
|
||||
v_search = self.harm_int.interpolate_fill(v_search)
|
||||
|
||||
# Update solid using the new rest shape v_search
|
||||
self.solid.update_rest_shape(v_search)
|
||||
|
||||
# Update equilibrium deformation
|
||||
self.solid.find_equilibrium(verbose=verbose)
|
||||
|
||||
|
||||
def compute_obj(self):
|
||||
'''
|
||||
Compute Objective at the current params
|
||||
|
||||
Output:
|
||||
- obj : Accumulated objective value
|
||||
'''
|
||||
|
||||
obj = self.tgt_fit.obj(self.solid.v_def.clone().detach())
|
||||
obj += self.neo_reg.obj(self.solid, self.params)
|
||||
return obj
|
||||
|
||||
def line_search_step(self, step_size_init, max_l_iter):
|
||||
'''
|
||||
Perform line search to take a step in the BFGS descent direction at the current optimization state
|
||||
|
||||
Input:
|
||||
- step_size_init : Initial value of step size
|
||||
- max_l_iter : Maximum iterations of line search
|
||||
|
||||
Updated attributes:
|
||||
- solid : Elastic solid, specifically, the rest shape and consequently the equilibrium deformation
|
||||
- params, params_prev : torch Tensor of shape (#params,)
|
||||
- grad_prev : torch Tensor of shape (#params,)
|
||||
|
||||
Output:
|
||||
- obj_new : New objective value after taking the step
|
||||
- l_iter : Number of line search iterations taken
|
||||
'''
|
||||
|
||||
step_size = step_size_init
|
||||
# Compute previous objective for armijo rule
|
||||
obj_prev = self.compute_obj()
|
||||
success = False
|
||||
for l_iter in range(max_l_iter):
|
||||
step_size *= 0.5
|
||||
|
||||
# BFGS descent step - TODO
|
||||
descent_dir = - self.invB @ self.grad
|
||||
params_search = self.params + step_size * descent_dir
|
||||
|
||||
# Try taking a step
|
||||
try:
|
||||
# Save solid rest and def states in case steps fail
|
||||
rest_prev, def_prev = self.solid.v_rest.clone().detach(), self.solid.v_def.clone().detach()
|
||||
|
||||
# Take a Step - TODO
|
||||
self.set_params(params_search,False)
|
||||
|
||||
# Compute new objective - TODO
|
||||
obj_search = self.compute_obj()
|
||||
|
||||
assert not torch.isnan(obj_search), "nan encountered"
|
||||
|
||||
# Evaluate armijo condition - TODO
|
||||
armijo = obj_search < obj_prev + 10e-4 * step_size*((params_search*self.grad).sum())
|
||||
|
||||
if armijo or l_iter == max_l_iter-1:
|
||||
self.params_prev = self.params.clone().detach() # BFGS bookkeeping
|
||||
self.grad_prev = self.grad.clone() # BFGS bookkeeping
|
||||
self.params, obj_new = params_search, obj_search # params at t becomes params at t+1
|
||||
success = True
|
||||
break
|
||||
|
||||
# Fallback to previous in case we take a step that is too large
|
||||
except Exception as e:
|
||||
print("An exception occured: {}. \nHalving the step.".format(e))
|
||||
self.solid.update_rest_shape(rest_prev) # fall back to non NaN values
|
||||
self.solid.update_def_shape(def_prev) # faster convergence fo the next equilibrium
|
||||
if l_iter == max_l_iter - 1:
|
||||
return obj_prev, l_iter, success
|
||||
return obj_new, l_iter, success
|
||||
|
||||
def optimize(self, step_size_init=1e-3, max_l_iter=10, n_optim_steps=10):
|
||||
'''
|
||||
Run BFGS to optimize over the objective J.
|
||||
|
||||
Input:
|
||||
- step_size_init : Initial value of step size
|
||||
- max_l_iter : Maximum iterations of line search
|
||||
|
||||
Updated attributes:
|
||||
- objectives : Tensor tracking objectives across optimization steps
|
||||
- grad_mags : Tensor tracking norms of the gradient across optimization steps
|
||||
'''
|
||||
|
||||
self.objectives = torch.zeros(size=(n_optim_steps+1,))
|
||||
self.grad_mags = torch.zeros(size=(n_optim_steps,))
|
||||
|
||||
self.objectives[0] = self.compute_obj()
|
||||
|
||||
startTime = time.time()
|
||||
for i in range(n_optim_steps):
|
||||
# Update the gradients
|
||||
self.grad_mags[i] = torch.linalg.norm(self.compute_gradient())
|
||||
|
||||
# Update quatities of BFGS
|
||||
if i >= 1:
|
||||
self.update_BFGS()
|
||||
|
||||
# Line Search
|
||||
'''
|
||||
Updates self.objectives[i+1], l_iter, success on returning
|
||||
'''
|
||||
self.objectives[i+1], l_iter, success = self.line_search_step(step_size_init, max_l_iter)
|
||||
|
||||
if not success:
|
||||
print("Line search can't find a step to take")
|
||||
return
|
||||
|
||||
display.clear_output(wait=True)
|
||||
# Remaining time
|
||||
curr_time = (time.time() - startTime)
|
||||
rem_time = (n_optim_steps - i - 1) / (i + 1) * curr_time
|
||||
print("Objective after {} optimization step(s): {:.4e}".format(i+1, self.objectives[i+1]))
|
||||
print(" Line search Iters: " + str(l_iter))
|
||||
print("Elapsed time: {:.1f}s. \nEstimated remaining time: {:.1f}s\n".format(curr_time, rem_time))
|
||||
|
||||
# Plot the resulting mesh
|
||||
rot = np.array(
|
||||
[[1, 0, 0 ],
|
||||
[0, 0, 1],
|
||||
[0, -1, 0 ]]
|
||||
)
|
||||
aabb = np.max(to_numpy(self.solid.v_rest), axis=0) - np.min(to_numpy(self.solid.v_rest), axis=0)
|
||||
length_scale = np.mean(aabb)
|
||||
plot_torch_solid(self.solid, self.beNP, rot, length_scale, target_mesh=self.vt_surf)
|
||||
|
||||
# # Early Termination
|
||||
# if (self.objectives[i] - self.objectives[i+1]) < 1e-3 * self.objectives[i]:
|
||||
# print("Decrease regularization weight.")
|
||||
# self.neo_reg.weight_reg *= 0.5
|
||||
# invB = torch.eye(3 * self.params_idx.shape[0])
|
||||
|
||||
# if (self.objectives[i] - self.objectives[i+1]) < 1e-5 * self.objectives[i]:
|
||||
# print("Stop optimization due to non satisfactory relative progress on the objective.")
|
||||
# break
|
||||
|
||||
|
||||
def gradient_helper_autograd(solid, dJ_dx, params_tmp, params_idx, harm_int):
|
||||
'''
|
||||
Computes a pytorch computational flow to compute the gradient of the forward simulation through automatic differentiation
|
||||
'''
|
||||
# Adjoint state y
|
||||
adjoint = compute_adjoint(solid, dJ_dx)
|
||||
|
||||
# Define the variable to collect the gradient of f_tot. y
|
||||
params_collect = params_tmp.clone()
|
||||
params_collect.requires_grad = True
|
||||
|
||||
# Model f_tot.y as a differentiable pytorch function of params to collect gradient from auto_grad
|
||||
dot_prod = adjoint_dot_forces(params_collect, solid, adjoint, params_idx, harm_int)
|
||||
dot_prod.backward()
|
||||
dJ_dX = params_collect.grad.clone()
|
||||
params_collect.grad = None # Reset grad
|
||||
|
||||
return dJ_dX
|
||||
|
||||
def adjoint_dot_forces(params, solid, adjoint, params_idx, harm_int):
|
||||
'''
|
||||
Input:
|
||||
- params : array of shape (3*#params,)
|
||||
- solid : an elastic solid to copy with the deformation at equilibrium
|
||||
- adjoint : array of shape (3*nV,)
|
||||
- params_idx : parameters index in the vertex list. Has shape (#params,)
|
||||
- harm_int : harmonic interpolator
|
||||
|
||||
Output:
|
||||
- dot_prod : dot product between forces at equilibrium and adjoint state vector
|
||||
'''
|
||||
|
||||
# From params, compute the full rest state using the harmonic interpolation
|
||||
v_vol = solid.v_rest.detach()
|
||||
v_vol[params_idx, :] = params.reshape(-1, 3)
|
||||
v_update = harm_int.interpolate_fill(v_vol)
|
||||
|
||||
#Initialize a solid with this rest state and the same deformed state of the solid
|
||||
|
||||
if "LinearElasticEnergy" in str(type(solid.ee)):
|
||||
ee_tmp = LinearElasticEnergy(solid.ee.young, solid.ee.poisson)
|
||||
elif "NeoHookeanElasticEnergy" in str(type(solid.ee)):
|
||||
ee_tmp = NeoHookeanElasticEnergy(solid.ee.young, solid.ee.poisson)
|
||||
|
||||
solid_tmp = ElasticSolid(v_update, solid.t, ee_tmp, rho=solid.rho,
|
||||
pin_idx=solid.pin_idx, f_mass=solid.f_mass)
|
||||
solid_tmp.update_def_shape(solid.v_def.clone().detach())
|
||||
|
||||
return adjoint.detach() @ (solid_tmp.f + solid_tmp.f_ext).reshape(-1,)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
import torch
|
||||
import igl
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import meshplot as mp
|
||||
import time
|
||||
from scipy.sparse.linalg import cg
|
||||
from scipy.sparse.linalg import LinearOperator
|
||||
|
||||
torch.set_default_dtype(torch.float64)
|
||||
|
||||
def to_numpy(tensor):
|
||||
return tensor.detach().clone().numpy()
|
||||
|
||||
def get_boundary_and_interior(vlen, t):
|
||||
bv = np.unique(igl.boundary_facets(t))
|
||||
vIdx = np.arange(vlen)
|
||||
iv = vIdx[np.invert(np.in1d(vIdx, bv))]
|
||||
return bv, iv
|
||||
|
||||
|
||||
def conjugate_gradient(L_method, b):
|
||||
'''
|
||||
Finds an inexact Newton descent direction using Conjugate Gradient (CG)
|
||||
Solves partially L(x) = b where A is positive definite, using CG.
|
||||
The method should be implemented to check whether the added direction is
|
||||
an ascent direction or not, and whether the residuals are small enough.
|
||||
Details can be found in the handout.
|
||||
|
||||
Input:
|
||||
- L_method : a method that computes the Hessian vector product. It should
|
||||
take an array of shape (n,) and return an array of shape (n,)
|
||||
- b : right hand side of the linear system (n,)
|
||||
|
||||
Output:
|
||||
- p_star : torch array of shape (n,) solving the linear system approximately
|
||||
'''
|
||||
|
||||
n = b.shape[0]
|
||||
p_star = torch.zeros_like(b)
|
||||
residual = - b
|
||||
direction = - residual.clone()
|
||||
grad_norm = torch.linalg.norm(b)
|
||||
|
||||
# Reusable quantities
|
||||
L_direction = L_method(direction) # L d
|
||||
res_norm_sq = torch.sum(residual ** 2, dim=0) # r^T r
|
||||
dir_norm_sq_L = direction @ L_direction
|
||||
|
||||
for k in range(n):
|
||||
if dir_norm_sq_L <= 0:
|
||||
if k == 0:
|
||||
return b
|
||||
else:
|
||||
return p_star
|
||||
# Compute the new guess for the solution
|
||||
alpha = res_norm_sq / dir_norm_sq_L
|
||||
p_star = p_star + direction * alpha
|
||||
residual = residual + L_direction * alpha
|
||||
|
||||
# Check that the new residual norm is small enough
|
||||
new_res_norm_sq = torch.sum(residual ** 2, dim=0)
|
||||
if torch.sqrt(new_res_norm_sq) < min(0.5, torch.sqrt(grad_norm))*grad_norm:
|
||||
break
|
||||
|
||||
# Update quantities
|
||||
beta = new_res_norm_sq / res_norm_sq
|
||||
direction = - residual + direction * beta
|
||||
L_direction = L_method(direction)
|
||||
res_norm_sq = new_res_norm_sq
|
||||
dir_norm_sq_L = direction@L_direction
|
||||
|
||||
# print("Num conjugate gradient steps: " + str(k))
|
||||
return p_star
|
||||
|
||||
def linear_solve(L_method, b):
|
||||
'''
|
||||
Solves Ax = b where A is positive definite.
|
||||
A has shape (n, n), x and b have shape (n,).
|
||||
|
||||
Input:
|
||||
- L_method : a method that takes x and returns the product Ax
|
||||
- b : right hand side of the linear system
|
||||
Output:
|
||||
- x_star : np array of shape (n,) solving the linear system
|
||||
'''
|
||||
dim = b.shape[0]
|
||||
def LHSnp(x):
|
||||
return to_numpy(L_method(torch.tensor(x)))
|
||||
LHS_op = LinearOperator((dim, dim), matvec=LHSnp)
|
||||
x_star_np, _ = cg(LHS_op, to_numpy(b))
|
||||
x_star = torch.tensor(x_star_np)
|
||||
return x_star
|
||||
|
||||
def compute_inverse_approximate_hessian_matrix(sk, yk, invB_prev):
|
||||
'''
|
||||
Input:
|
||||
- sk : previous step x_{k+1} - x_k, shape (n, 1)
|
||||
- yk : grad(f)_{k+1} - grad(f)_{k}, shape (n, 1)
|
||||
- invB_prev : previous Hessian estimate Bk, shape (n, n)
|
||||
|
||||
Output:
|
||||
- invB_new : previous Hessian estimate Bk, shape (n, n)
|
||||
'''
|
||||
invB_new = invB_prev.clone()
|
||||
invB_new += (sk.T @ yk + yk.T @ invB_prev @ yk) / ((sk.T @ yk) ** 2) * (sk @ sk.T)
|
||||
prod = (invB_prev @ yk) @ sk.T
|
||||
invB_new -= (prod + prod.T) / (sk.T @ yk)
|
||||
return invB_new
|
||||
|
||||
|
||||
def equilibrium_convergence_report_NCG(solid, v_init, n_steps, thresh=1e-3):
|
||||
'''
|
||||
Finds the equilibrium by minimizing the total energy using Newton CG.
|
||||
|
||||
Input:
|
||||
- solid : an elastic solid to optimize
|
||||
- v_init : the initial guess for the equilibrium position
|
||||
- n_step : number of optimization steps
|
||||
- thresh : threshold to stop the optimization process on the gradient's magnitude
|
||||
|
||||
Ouput:
|
||||
- report : a dictionary containing various quantities of interest
|
||||
'''
|
||||
|
||||
solid.update_def_shape(v_init)
|
||||
|
||||
energies_el = np.zeros(shape=(n_steps+1,))
|
||||
energies_ext = np.zeros(shape=(n_steps+1,))
|
||||
residuals = np.zeros(shape=(n_steps+1,))
|
||||
times = np.zeros(shape=(n_steps+1,))
|
||||
energies_el[0] = solid.energy_el
|
||||
energies_ext[0] = solid.energy_ext
|
||||
residuals[0] = torch.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
idx_stop = n_steps
|
||||
|
||||
t_start = time.time()
|
||||
for i in range(n_steps):
|
||||
# Take a Newton step
|
||||
solid.equilibrium_step()
|
||||
|
||||
# Measure the force residuals
|
||||
energies_el[i+1] = solid.energy_el
|
||||
energies_ext[i+1] = solid.energy_ext
|
||||
residuals[i+1] = torch.linalg.norm((solid.f + solid.f_ext)[solid.free_idx, :])
|
||||
|
||||
if residuals[i+1] < thresh:
|
||||
residuals[i+1:] = residuals[i+1]
|
||||
energies_el[i+1:] = energies_el[i+1]
|
||||
energies_ext[i+1:] = energies_ext[i+1]
|
||||
idx_stop = i
|
||||
break
|
||||
|
||||
times[i+1] = time.time() - t_start
|
||||
|
||||
report = {}
|
||||
report['energies_el'] = energies_el
|
||||
report['energies_ext'] = energies_ext
|
||||
report['residuals'] = residuals
|
||||
report['times'] = times
|
||||
report['idx_stop'] = idx_stop
|
||||
|
||||
return report
|
||||
|
||||
def fd_validation_ext(solid):
|
||||
epsilons = torch.logspace(-9, -3, 100)
|
||||
perturb_global = 1e-3 * (2. * torch.rand(size=solid.v_def.shape) - 1.)
|
||||
solid.displace(perturb_global)
|
||||
v_def = solid.v_def.clone()
|
||||
perturb = 2. * torch.rand(size=solid.v_def.shape) - 1.
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
grad = torch.zeros(solid.f_ext.shape)
|
||||
grad[solid.free_idx] = -solid.f_ext[solid.free_idx]
|
||||
an_delta_E = (grad*perturb).sum()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
E1 = solid.energy_ext.clone()
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
E2 = solid.energy_ext.clone()
|
||||
|
||||
# Compute error
|
||||
fd_delta_E = (E1 - E2)/(2*eps)
|
||||
errors.append(abs(fd_delta_E - an_delta_E)/abs(an_delta_E))
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
def fd_validation_elastic(solid):
|
||||
epsilons = torch.logspace(-9, -3, 100)
|
||||
perturb_global = 1e-3 * (2. * torch.rand(size=solid.v_def.shape) - 1.)
|
||||
solid.displace(perturb_global)
|
||||
|
||||
v_def = solid.v_def.clone()
|
||||
solid.make_elastic_forces()
|
||||
|
||||
perturb = 2. * torch.rand(size=solid.v_def.shape) - 1.
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
solid.make_elastic_forces()
|
||||
grad = torch.zeros(solid.f.shape)
|
||||
grad[solid.free_idx] = -solid.f[solid.free_idx]
|
||||
an_delta_E = (grad*perturb).sum()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
E1 = solid.energy_el.clone()
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
E2 = solid.energy_el.clone()
|
||||
|
||||
# Compute error
|
||||
fd_delta_E = (E1 - E2)/(2*eps)
|
||||
errors.append(abs(fd_delta_E - an_delta_E)/abs(an_delta_E))
|
||||
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
def fd_validation_elastic_differentials(solid):
|
||||
epsilons = torch.logspace(-9, 3, 500)
|
||||
perturb_global = 1e-3 * (2. * torch.rand(size=solid.v_def.shape) - 1.)
|
||||
solid.displace(perturb_global)
|
||||
|
||||
v_def = solid.v_def.clone()
|
||||
|
||||
perturb = 2. * torch.rand(size=solid.v_def.shape) - 1.
|
||||
errors = []
|
||||
for eps in epsilons:
|
||||
# Back to original
|
||||
solid.update_def_shape(v_def)
|
||||
perturb_0s = torch.zeros_like(perturb)
|
||||
perturb_0s[solid.free_idx] = perturb[solid.free_idx]
|
||||
an_df = solid.compute_force_differentials(perturb_0s)[solid.free_idx, :]
|
||||
an_df_full = torch.zeros(solid.f.shape)
|
||||
an_df_full[solid.free_idx] = an_df.clone()
|
||||
|
||||
# One step forward
|
||||
solid.displace(perturb * eps)
|
||||
f1 = solid.f[solid.free_idx, :]
|
||||
f1_full = torch.zeros(solid.f.shape)
|
||||
f1_full[solid.free_idx] = f1
|
||||
|
||||
# Two steps backward
|
||||
solid.displace(-2*perturb * eps)
|
||||
f2 = solid.f[solid.free_idx, :]
|
||||
f2_full = torch.zeros(solid.f.shape)
|
||||
f2_full[solid.free_idx] = f2
|
||||
|
||||
# Compute error
|
||||
fd_delta_f = (f1_full - f2_full)/(2*eps)
|
||||
norm_an_df = torch.linalg.norm(an_df_full)
|
||||
norm_error = torch.linalg.norm(an_df_full - fd_delta_f)
|
||||
errors.append(norm_error/norm_an_df)
|
||||
|
||||
plt.loglog(epsilons, errors)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
@@ -0,0 +1,30 @@
|
||||
import meshplot as mp
|
||||
import numpy as np
|
||||
# import jax.numpy as jnp
|
||||
import torch
|
||||
import torch
|
||||
|
||||
shadingOptions = {
|
||||
"flat":True,
|
||||
"wireframe":False,
|
||||
}
|
||||
|
||||
def to_numpy(tensor):
|
||||
return tensor.detach().clone().numpy()
|
||||
|
||||
def plot_torch_solid(solid, be, rot, length_scale, target_mesh=None):
|
||||
'''
|
||||
Input:
|
||||
- solid : elastic solid to visualize
|
||||
- be : boundary edges
|
||||
- rot : transformation matrix to apply (here we assume it is a rotation)
|
||||
- length_scale : length scale of the mesh, used to represent pinned vertices
|
||||
- target_mesh :
|
||||
'''
|
||||
p = mp.plot(to_numpy(solid.v_def) @ rot.T, to_numpy(solid.t), shading=shadingOptions)
|
||||
p.add_points(to_numpy(solid.v_def[solid.pin_idx, :]) @ rot.T, shading={"point_color":"black", "point_size": 0.1 * length_scale})
|
||||
forcesScale = 2 * torch.max(torch.linalg.norm(solid.f_ext, axis=1))
|
||||
p.add_lines(to_numpy(solid.v_def) @ rot.T, to_numpy(solid.v_def + solid.f_ext / forcesScale) @ rot.T)
|
||||
p.add_edges(to_numpy(solid.v_rest) @ rot.T, be, shading={"line_color": "blue"})
|
||||
if not target_mesh is None:
|
||||
p.add_edges(to_numpy(target_mesh) @ rot.T, be, shading={"line_color": "red"})
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 284 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 631 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 700 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 910 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 991 KiB |
@@ -0,0 +1,85 @@
|
||||
import numpy as np
|
||||
import torch
|
||||
import sys as _sys
|
||||
_sys.path.append("../src/")
|
||||
from elasticenergy import *
|
||||
from elasticsolid import *
|
||||
from adjoint_sensitivity import *
|
||||
from vis_utils import *
|
||||
from objectives import *
|
||||
from harmonic_interpolator import *
|
||||
from shape_optimizer import *
|
||||
from utils import *
|
||||
import json, pytest
|
||||
|
||||
torch.set_default_dtype(torch.float64)
|
||||
eps = 1E-6
|
||||
|
||||
with open('test_data4_beam.json', 'r') as infile:
|
||||
homework_datas = json.load(infile)
|
||||
|
||||
@pytest.mark.timeout(2)
|
||||
@pytest.mark.parametrize("data", homework_datas[0])
|
||||
def test_adjoint(data):
|
||||
young, poisson, v, t, rho, pin_idx, force_mass, v_rest, v_def, dJ_dx_U, adjoint_gt = data
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(torch.tensor(v), torch.tensor(np.array(t), dtype=torch.int64), ee, rho=rho, pin_idx=torch.tensor(pin_idx, dtype=torch.int64), f_mass=torch.tensor(force_mass))
|
||||
es.update_rest_shape(torch.tensor(v_rest))
|
||||
es.update_def_shape(torch.tensor(v_def))
|
||||
assert torch.linalg.norm(compute_adjoint(es, torch.tensor(dJ_dx_U)) - torch.tensor(adjoint_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(2)
|
||||
@pytest.mark.parametrize("data", homework_datas[1])
|
||||
def test_obj(data):
|
||||
v, vt, bv, obj_gt = data
|
||||
assert torch.linalg.norm(objective_target_BV(torch.tensor(v), torch.tensor(vt), torch.tensor(bv)) - torch.tensor(obj_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(2)
|
||||
@pytest.mark.parametrize("data", homework_datas[2])
|
||||
def test_obj_grad(data):
|
||||
v, vt, bv, obj_grad_gt = data
|
||||
assert torch.linalg.norm(grad_objective_target_BV(torch.tensor(v), torch.tensor(vt), torch.tensor(bv)) - torch.tensor(obj_grad_gt)) < eps
|
||||
|
||||
@pytest.mark.timeout(2)
|
||||
@pytest.mark.parametrize("data", homework_datas[3])
|
||||
def test_pt_load(data):
|
||||
young, poisson, v, t, rho, pin_idx, force_mass, v_rest, v_def, f_point_idx, f_point, f_point_gt, f_ext_gt = data
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(torch.tensor(v), torch.tensor(np.array(t), dtype=torch.int64), ee, rho=rho, pin_idx=torch.tensor(pin_idx, dtype=torch.int64), f_mass=torch.tensor(force_mass))
|
||||
es.update_rest_shape(torch.tensor(v_rest))
|
||||
es.update_def_shape(torch.tensor(v_def))
|
||||
es.add_point_load(torch.tensor(f_point_idx), torch.tensor(f_point))
|
||||
assert torch.linalg.norm(es.f_point - torch.tensor(f_point_gt)) < eps
|
||||
assert torch.linalg.norm(es.f_ext - torch.tensor(f_ext_gt)) < eps
|
||||
|
||||
|
||||
@pytest.mark.parametrize("data", homework_datas[4])
|
||||
def test_set_params(data):
|
||||
young, poisson, v, t, vt_surf, rho, pin_idx, force_mass, v_rest, v_def, new_params, v_rest_gt, v_def_gt = data
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(torch.tensor(v_rest), torch.tensor(np.array(t), dtype=torch.int64), ee, rho=rho, pin_idx=torch.tensor(pin_idx, dtype=torch.int64), f_mass=torch.tensor(force_mass))
|
||||
|
||||
es.update_def_shape(torch.tensor(v_def))
|
||||
optimizer = ShapeOptimizer(es, torch.tensor(vt_surf), weight_reg=0.)
|
||||
optimizer.set_params(torch.tensor(new_params))
|
||||
assert torch.linalg.norm(optimizer.solid.v_rest - torch.tensor(v_rest_gt)) < eps
|
||||
assert torch.linalg.norm(optimizer.solid.v_def - torch.tensor(v_def_gt)) < eps
|
||||
|
||||
@pytest.mark.parametrize("data", homework_datas[5])
|
||||
def test_line_search(data):
|
||||
young, poisson, v, t, vt_surf, rho, pin_idx, force_mass, v_rest, v_def, obj_gt, l_iter_gt, success_gt = data
|
||||
|
||||
ee = NeoHookeanElasticEnergy(young, poisson)
|
||||
|
||||
es = ElasticSolid(torch.tensor(v_rest), torch.tensor(np.array(t), dtype=torch.int64), ee, rho=rho, pin_idx=torch.tensor(pin_idx, dtype=torch.int64), f_mass=torch.tensor(force_mass))
|
||||
# es.update_rest_shape(torch.tensor(v_rest))
|
||||
es.update_def_shape(torch.tensor(v_def))
|
||||
optimizer = ShapeOptimizer(es, torch.tensor(vt_surf), weight_reg=0.)
|
||||
obj, l_iter, success = optimizer.line_search_step(1e-2, 10)
|
||||
assert torch.linalg.norm(obj - torch.tensor(obj_gt)) < eps
|
||||
assert l_iter == l_iter_gt
|
||||
assert success == success_gt
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
[[[300000000.0, 0.2, [[1.92892740885417, 0.795891927083333, 7.06959962671885], [1.38140950520833, 1.12016276041667, 6.56891766057302], [1.77776204427083, 1.23249348958333, 6.5171683929949], [3.36708333333333, 1.2026953125, 6.34609376734385], [3.6378271484375, 0.736062825520833, 6.5233158539324], [2.94625162760417, 0.811892903645833, 6.42714804794282], [1.21115234375, 3.2785107421875, 4.03569032496105], [1.21115234375, 3.05222330729167, 4.03569032496105], [1.41037272135417, 3.22219563802083, 3.96712851669282], [1.17717610677083, 3.2785107421875, 3.7849456960548], [1.17717610677083, 3.05222330729167, 3.7849456960548], [0.826608072916667, 3.297607421875, 3.81374004826833], [0.906559244791667, 3.06875651041667, 4.0594486664324], [-0.165138346354167, 3.06035970052083, 4.22297080184907], [0.207609049479167, 2.72546223958333, 4.4538354665626], [0.426946614583333, 3.14258951822917, 4.07493613388032], [0.136866861979167, 3.15456380208333, 3.56399293726573], [-0.284313151041667, 2.76587565104167, 3.67290386662772], [0.477122395833333, 2.6718603515625, 4.01503704533865], [0.0884342447916667, 2.43097819010417, 3.90376873479177], [0.1993896484375, 2.6778466796875, 3.48202435002615], [0.114910481770833, 2.01370768229167, 3.82798341578135], [-0.3699169921875, 2.3461474609375, 3.66176983342458], [0.826608072916667, 2.83990559895833, 3.81374004826833], [0.746658528645833, 3.06875651041667, 3.56803143010427], [1.07312174479167, 0.186591796875, 3.35497946884125], [0.9015087890625, 0.186591796875, 3.12470684514333], [1.20571940104167, 0.2429052734375, 3.13923911239593], [1.07312174479167, 0.412877604166667, 3.35497946884125], [0.806204427083333, 0.396344401041667, 3.63202109481782], [0.616028645833333, 0.167493489583333, 3.41086997177093], [0.3102978515625, 0.322511393229167, 3.97484458114593], [-0.206339518229167, 0.720045572916667, 5.0712231618751], [-0.866873372395833, 0.563816731770833, 4.36135377710948], [-0.273390299479167, 0.4047412109375, 4.2340454275001], [0.155592447916667, 0.739638671875, 4.44255210067718], [-0.394640299479167, 1.118955078125, 3.66679506128917], [0.114910481770833, 1.45139322916667, 3.82798341578135], [-0.0198177083333333, 1.03412272135417, 3.91484336044282], [-1.1627880859375, 0.668907877604167, 3.70662782496105], [-0.448800455729167, 0.699225260416667, 3.70633628036468], [-1.65739908854167, 0.4868603515625, 4.67379762476573], [0.616028645833333, 0.625196940104167, 3.41086997177093], [0.9015087890625, 0.412877604166667, 3.12470684514333], [0.4258544921875, 0.396344401041667, 3.18971905217458], [-1.25579336387079, 2.94434041341147, 0.247196960449218], [-1.54755361777704, 2.95571980794272, 0.0], [-1.09422964316767, 3.46414021809897, 0.0], [-1.25579336387079, 3.9889766438802, 0.247196960449218], [-1.60864858848017, 3.4709395345052, 0.342559991040513], [-1.54755361777704, 3.97978230794272, 0.0], [-2.42104549153645, 3.65468636067708, 2.9570504222104], [-1.66876912434895, 3.16619026692708, 2.68253211166352], [-1.72982670124777, 3.68813736979167, 1.90246897460907], [-3.33207438151042, 3.12324055989583, 3.52005433863292], [-2.04028645833333, 3.24179850260417, 4.17553794052093], [-2.82052490234375, 2.88153157552083, 4.66295208440115], [-2.6843221842448, 3.65153190104167, 1.9230649218747], [-3.01930135091147, 3.05401643880208, 2.43617029525727], [-1.9243285201208, 4.16030232747395, 0.0], [-3.1018050733139, 3.70525227864583, 0.0], [-2.17311557100355, 3.8179404296875, 0.524649200439453], [-1.9243285201208, 2.78452596028645, 0.0], [-2.17311557100355, 3.10023990885417, 0.524649200439453], [-3.1018050733139, 3.19518880208333, 0.0], [-2.24000845176142, 3.47388875325522, 0.0], [-3.21087890625, 2.32591145833333, 2.55441530054698], [-4.38078694661458, 2.22052734375, 3.06782899683605], [-2.6704286295573, 2.86222135416667, 1.78254087402313], [-2.26702498372397, 2.56552034505208, 2.1616521067807], [-2.89291433115097, 3.38942643229167, 0.981263467152913], [-1.65064127604167, 2.49373697916667, 2.88164450790375], [-1.67526810749777, 2.98055729166667, 1.68948270751923], [-2.42513210458847, 3.02414518229167, 1.00103408177694], [-1.95734987802597, 3.44676822916667, 1.02080471165975], [-2.42513210458847, 3.81204947916667, 1.00103408177694], [2.92133138020833, 0.893297526041667, 8.61891277776052], [3.2291259765625, 1.302109375, 8.75000083114593], [2.63646647135417, 1.34214680989583, 8.80626547958343], [4.520048828125, 0.773118489583333, 6.23344240015635], [4.7681591796875, 0.602462565104167, 6.3074926931251], [4.31585123697917, 0.64810546875, 6.36416464950532], [2.18455891927083, 1.58300618489583, 6.51337526148448], [1.97090169270833, 1.90125, 6.60278240666677], [2.68102376302083, 1.90736165364583, 6.6796508962501], [4.43249674479167, 0.947452799479167, 6.42411419377615], [4.80994954427083, 0.709705403645833, 6.3289701508074], [-0.16156494140625, -0.49367919921875, 0.247196960449218], [-0.4533251953125, -0.48448486328125, 0.0], [0.0, 0.0, 0.0], [-0.16156494140625, 0.48864501953125, 0.247196960449218], [-0.4533251953125, 0.4772Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
[[[300000000.0, 0.2, [[0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [2.0, 1.0, 0.0], [3.0, 1.0, 0.0], [4.0, 1.0, 0.0], [5.0, 1.0, 0.0], [6.0, 1.0, 0.0], [7.0, 1.0, 0.0], [8.0, 1.0, 0.0], [9.0, 1.0, 0.0], [10.0, 1.0, 0.0], [0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [3.0, 0.0, 0.0], [4.0, 0.0, 0.0], [5.0, 0.0, 0.0], [6.0, 0.0, 0.0], [7.0, 0.0, 0.0], [8.0, 0.0, 0.0], [9.0, 0.0, 0.0], [10.0, 0.0, 0.0], [0.0, 1.0, 2.0], [1.0, 1.0, 2.0], [2.0, 1.0, 2.0], [3.0, 1.0, 2.0], [4.0, 1.0, 2.0], [5.0, 1.0, 2.0], [6.0, 1.0, 2.0], [7.0, 1.0, 2.0], [8.0, 1.0, 2.0], [9.0, 1.0, 2.0], [10.0, 1.0, 2.0], [0.0, 2.0, 2.0], [1.0, 2.0, 2.0], [2.0, 2.0, 2.0], [3.0, 2.0, 2.0], [4.0, 2.0, 2.0], [5.0, 2.0, 2.0], [6.0, 2.0, 2.0], [7.0, 2.0, 2.0], [8.0, 2.0, 2.0], [9.0, 2.0, 2.0], [10.0, 2.0, 2.0], [1.0, 0.0, 1.0], [2.0, 0.0, 1.0], [3.0, 0.0, 1.0], [4.0, 0.0, 1.0], [5.0, 0.0, 1.0], [6.0, 0.0, 1.0], [7.0, 0.0, 1.0], [8.0, 0.0, 1.0], [9.0, 0.0, 1.0], [10.0, 0.0, 1.0], [0.0, 0.0, 2.0], [1.0, 0.0, 2.0], [2.0, 0.0, 2.0], [3.0, 0.0, 2.0], [4.0, 0.0, 2.0], [5.0, 0.0, 2.0], [6.0, 0.0, 2.0], [7.0, 0.0, 2.0], [8.0, 0.0, 2.0], [9.0, 0.0, 2.0], [10.0, 0.0, 2.0], [10.0, 1.0, 1.0], [10.0, 2.0, 0.0], [9.0, 2.0, 0.0], [8.0, 2.0, 0.0], [7.0, 2.0, 0.0], [6.0, 2.0, 0.0], [5.0, 2.0, 0.0], [4.0, 2.0, 0.0], [3.0, 2.0, 0.0], [2.0, 2.0, 0.0], [1.0, 2.0, 0.0], [0.0, 2.0, 0.0], [10.0, 2.0, 1.0], [9.0, 2.0, 1.0], [8.0, 2.0, 1.0], [7.0, 2.0, 1.0], [6.0, 2.0, 1.0], [5.0, 2.0, 1.0], [4.0, 2.0, 1.0], [3.0, 2.0, 1.0], [2.0, 2.0, 1.0], [1.0, 2.0, 1.0], [0.0, 2.0, 1.0], [0.0, 1.0, 1.0], [0.0, 0.0, 1.0]], [[35, 85, 24, 23], [0, 86, 87, 88], [11, 12, 0, 44], [84, 37, 36, 25], [86, 34, 22, 23], [47, 84, 3, 46], [60, 27, 48, 59], [45, 13, 1, 2], [8, 30, 7, 51], [84, 36, 24, 25], [18, 6, 17, 50], [60, 27, 49, 48], [48, 27, 26, 59], [84, 4, 3, 72], [2, 84, 3, 73], [27, 60, 49, 28], [31, 30, 42, 78], [22, 44, 89, 88], [27, 38, 39, 81], [9, 53, 52, 20], [47, 84, 46, 25], [47, 84, 4, 3], [6, 49, 17, 50], [49, 27, 28, 5], [84, 3, 73, 72], [87, 86, 22, 88], [76, 0, 75, 86], [12, 45, 13, 1], [0, 11, 44, 89], [86, 34, 33, 22], [0, 1, 86, 88], [8, 52, 19, 20], [28, 27, 81, 5], [28, 81, 6, 5], [47, 48, 15, 4], [24, 46, 57, 45], [14, 47, 15, 3], [15, 47, 4, 3], [1, 0, 44, 88], [0, 1, 75, 86], [7, 29, 6, 50], [34, 85, 35, 23], [44, 0, 89, 88], [75, 1, 85, 86], [79, 29, 40, 80], [84, 4, 72, 83], [29, 61, 28, 50], [49, 28, 6, 5], [22, 23, 44, 88], [76, 0, 86, 87], [75, 1, 74, 85], [47, 84, 25, 26], [1, 85, 86, 23], [2, 73, 74, 85], [2, 84, 73, 85], [2, 23, 85, 1], [1, 2, 74, 85], [22, 86, 23, 88], [29, 79, 40, 41], [27, 4, 26, 82], [29, 28, 40, 80], [46, 57, 58, 25], [14, 47, 3, 46], [87, 86, 33, 22], [86, 85, 34, 23], [12, 1, 0, 44], [54, 22, 44, 89], [85, 84, 35, 24], [12, 45, 1, 44], [45, 24, 23, 56], [4, 72, 83, 71], [35, 84, 36, 24], [2, 84, 85, 24], [24, 2, 23, 85], [84, 83, 37, 26], [9, 10, 65, 53], [58, 47, 25, 26], [47, 46, 58, 25], [45, 24, 56, 57], [22, 55, 54, 44], [84, 47, 4, 26], [84, 37, 25, 26], [22, 23, 55, 44], [45, 23, 1, 44], [2, 24, 23, 45], [2, 23, 1, 45], [23, 45, 56, 44], [23, 56, 55, 44], [86, 1, 23, 88], [23, 1, 44, 88], [46, 24, 2, 45], [2, 14, 3, 46], [9, 10, 53, 21], [13, 14, 2, 46], [45, 13, 2, 46], [48, 27, 4, 26], [47, 48, 4, 26], [46, 24, 57, 25], [84, 4, 83, 26], [46, 84, 2, 25], [8, 79, 30, 78], [46, 24, 25, 2], [2, 84, 24, 25], [84, 46, 2, 3], [47, 48, 26, 59], [58, 47, 26, 59], [30, 8, 52, 51], [49, 60, 61, 28], [32, 31, 77, 65], [30, 79, 29, 41], [39, 28, 81, 80], [62, 61, 29, 50], [29, 62, 50, 51], [40, 28, 39, 80], [32, 31, 65, 53], [8, 79, 67, 68], [81, 70, 69, 6], [4, 83, 82, 71], [31, 42, 77, 78], [28, 27, 39, 81], [4, 83, 26, 82], [32, 31, 43, 77], [8, 79, 78, 67], [7, 6, 18, 50], [27, 26, 38, 82], [27, 38, 81, 82], [27, 49, 48, 5], [64, 63, 31, 52], [81, 70, 6, 5], [28, 81, 80, 6], [80, 69, 7, 6], [83, 37, 26, 82], [26, 37, 38, 82], [31, 42, 43, 77], [8, 30, 31, 78], [30, 79, 41, 78], [30, 41, 42, 78], [66, 77, 9, 10], [31, 8, 9, 52], [61, 49, 28, 50], [70, 81, 82, 5], [48, 15, 4, 16], [80, 81, 69, 6], [49, 48, 5, 16], [78, 67, 66, 9], [78, 8, 67, 9], [49, 5, 17, 16], [77, 9, 10, 65], [77, 78, 66, 9], [31, 8, 78, 9], [77, 31, 78, 65], [78, 31, 9, 65], [77, 78, 9, 65], [8, 9, 52, 20], [81, 27, 82, 5], [70, 82, 71, 5], [68, 80, 69, 7], [63, 30, 52, 51], [27, 4, 82, 5], [82, 4, 71, 5], [79, 29, 80, 7], [27, 48, 4, 5], [63, 62, 30, 51], [79, 80, 68, 7], [8, 79, 68, 7], [6, 49, 5, 17], [79, 8, 30, 7], [79, 30, 29, 7], [30, 62, 29, 51], [30, 29, 7, 51], [29, 80, 7, 6], [29, 28, 80, 6], [18, 7, 50, 51], [32, 64, 31, 53], [48, 4, 5, 16], [9, 53, 20, 21], [28, 49, 6, 50], [29, 28, 6, 50], [64, 31, 53, 52], [8, 52, 51, 19], [30, 8, 31, 52], [63, 30, 31, 52], [31, 9, 65, 52], [65, 9, 53, 52], [31, 65, 53, 52], [7, 29, 50, 51], [7, 8, 51, 19], [18, 7, 51, 19]], 131, [0, 11, 22, 33, 54, 76, 87, 88, 89], [0.0, 0.0, -1285.1100000000001], [[0.0, 1.0, 0.0], [1.036868033892407, 0.999825802896623, 0.034349523802574194], [2.0581123734974267, 0.9985427265446315, 0.08950Line truncated
|
||||
Reference in new issue
Block a user