mirror of
https://github.com/CHN-beta/nixos.git
synced 2026-01-12 11:10:44 +08:00
Compare commits
195 Commits
next-debug
...
vps6
| Author | SHA1 | Date | |
|---|---|---|---|
| b201a19c75 | |||
| 1854e294cf | |||
| b45a9c7a62 | |||
| 858f4c68aa | |||
| 37e6d70561 | |||
| f101038f4a | |||
| 412fac9692 | |||
| 4c7d17f001 | |||
| e8d80daee2 | |||
| 8aeb290d0f | |||
| 0f37c886a4 | |||
| 5940da526d | |||
| df2ac86e1a | |||
| 8bf7e2cb30 | |||
| 96f7056d16 | |||
| 5cc40727db | |||
| c4f8e5f61c | |||
| 03be19da5a | |||
| 7657fe3d14 | |||
| 9fee2a8e2a | |||
| db1e825cd6 | |||
| 670126ba0c | |||
| 92ddf86df1 | |||
| bd12de34b7 | |||
| a7b0906488 | |||
| 0ce31201a9 | |||
| 58d927b648 | |||
| 5efee599f7 | |||
| 2c833934e7 | |||
| c5dc456c35 | |||
| 7576726fbe | |||
| 6dfd6a8bf0 | |||
| eb68d8f8b1 | |||
| 46ae9f1aac | |||
| bb5aee5545 | |||
| a8833dac7f | |||
| d1b3f84cf3 | |||
| f813ffd053 | |||
| 00c99adca9 | |||
| ef58de9a1d | |||
| b9175a211f | |||
| 0cb7791b84 | |||
| 803af74404 | |||
| c5da42debd | |||
| e16f49b3f3 | |||
| f10c385f13 | |||
| f65ec24862 | |||
| 73261c3e3f | |||
| e50ad89bc2 | |||
| 5f4a79788d | |||
| 1360a3e9fa | |||
| d692bb8baf | |||
| dbcf7093aa | |||
| 7833f37588 | |||
| 673f241490 | |||
| a5be9adb53 | |||
| d6a1da17fb | |||
| 6e0e224530 | |||
| 1a007ab57f | |||
| da76976c3d | |||
| b46f928964 | |||
| 92fdc6c67d | |||
| 2534f35c4d | |||
| f9e376920c | |||
| c335a79b19 | |||
| 2d27006978 | |||
| dd1fb05917 | |||
| 6d814881c4 | |||
| ee18e481ba | |||
| 80ef9571db | |||
| de68b75268 | |||
| 423debe893 | |||
| 076a267ba4 | |||
| 2b88a1e32c | |||
| d8672ea42e | |||
| 7bd6e1f529 | |||
| 3d9af79476 | |||
| 734eedef2a | |||
| dd767f275a | |||
| 416eac129b | |||
| 11171c048a | |||
| e070046fc4 | |||
| b6ee3723d6 | |||
| b731752700 | |||
| 8f09a18dc5 | |||
| 1949ea7d78 | |||
| fb4a9644fc | |||
| 354f7d428e | |||
| 74b6155013 | |||
| 115a7f7753 | |||
| 98eb945684 | |||
| f1c8f8f1bb | |||
| 50da5ffa0b | |||
| b5a4aee761 | |||
| 64532717da | |||
| cc303a082c | |||
| 9e81d5a64f | |||
| c2d54a2b73 | |||
| 4e8452e9e0 | |||
| 9bf65a7a11 | |||
| 861d56ac7a | |||
| d51414e341 | |||
| 61afb76cfe | |||
| 1886f7e647 | |||
| 0a2e7e04e5 | |||
| 7dad1d3ec2 | |||
| 93ad14cc26 | |||
| b39fb0b8e0 | |||
| 30c25c499c | |||
| 4e8b18b417 | |||
| 4779d5e162 | |||
| 3b018c90e6 | |||
| 1dd9a61c95 | |||
| 705a43fa41 | |||
| e01a69e039 | |||
| 682bba4af9 | |||
| b04f527ee1 | |||
| c6d67af8c7 | |||
| 6275f6a519 | |||
| 5baa1ad173 | |||
| 1166dfbbcc | |||
| 5b183a5446 | |||
| 8e3eca38d7 | |||
| f74895585f | |||
| 4a0c5eee5a | |||
| 77296face8 | |||
| eb4cac0f14 | |||
| 7f343ce440 | |||
| 1b42c688ef | |||
| a94a7d368e | |||
| 1429950370 | |||
| f8b5a79afe | |||
| 759b3f7cae | |||
| a9931623b1 | |||
| d0213f48c1 | |||
| 24e8a94e7c | |||
| 0bc485a9b1 | |||
| ba523b61e8 | |||
| c40888a9b9 | |||
| e49d7b4055 | |||
| 4cba5c0160 | |||
| 837c6ff2d5 | |||
| f95c059ece | |||
| f6b40a3f3a | |||
| 5f0ea6f428 | |||
| d90e74c8df | |||
| c3647caacc | |||
| 5a07c21eac | |||
| f31dcbc640 | |||
| 37d90d0ed2 | |||
| 9ef2be228d | |||
| 4a2c0778e3 | |||
| a4c519c882 | |||
| 212869fe29 | |||
| 7afafdaac5 | |||
| 7c6709e70c | |||
| 0e972642be | |||
| 4939db84f0 | |||
| 964028dbe5 | |||
| 307fe81b15 | |||
| 9eea7cb2dc | |||
| 6dca3f3acf | |||
| 9d083566ed | |||
| 02b4a10ceb | |||
| 9617f19292 | |||
| b4b7ebf6fe | |||
| e8a45f91c8 | |||
| 0114927adf | |||
| 5a52292a97 | |||
| 578c2c9646 | |||
| 3059b012f7 | |||
| 9c80e754b2 | |||
| e908765aa8 | |||
| aa050c681a | |||
| e65fa2dc60 | |||
| 6011a2ba9f | |||
| 7281962001 | |||
| 215dbe7669 | |||
| 9f27c9dbc9 | |||
| 37c5678862 | |||
| f414a79a01 | |||
| 6690870fd3 | |||
| be49ac36ac | |||
| 0a55220e4e | |||
| 351623206d | |||
| 8848862e55 | |||
| 9b3db9f446 | |||
| a2166f8090 | |||
| eb01b0532c | |||
| bbad8cc650 | |||
| 779de003aa | |||
| b7ffc2cbe2 | |||
| 74872ec80a | |||
| 6c286cd402 | |||
| a24b38c4a6 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
result
|
||||
result-man
|
||||
result-*
|
||||
outputs
|
||||
.direnv
|
||||
build
|
||||
|
||||
6
bugs.md
6
bugs.md
@@ -1,6 +0,0 @@
|
||||
* pc: 使用 cachyos 内核时,一些外接显示器无法使用。
|
||||
* pc: 使用 amd 显卡时,原神明显卡顿。
|
||||
* 桌面壁纸无法保存
|
||||
* 桌面任务栏设置无法保存
|
||||
* xray 没有放行防火墙指定的端口
|
||||
* gtk 没有主题
|
||||
@@ -22,6 +22,7 @@ if [ -z "${BASHRC_SOURCED-}" ]; then
|
||||
export HPCSTAT_DATADIR=$HOME/linwei/chn/software/hpcstat/var/lib/hpcstat
|
||||
export HPCSTAT_SHAREDIR=$HOME/linwei/chn/software/hpcstat/share/hpcstat
|
||||
export HPCSTAT_SSH_BINDIR=$HOME/linwei/chn/software/hpcstat/bin
|
||||
export HPCSTAT_DUC_BINDIR=$HOME/linwei/chn/software/hpcstat/bin
|
||||
export HPCSTAT_BSUB=/opt/ibm/lsfsuite/lsf/10.1/linux2.6-glibc2.3-x86_64/bin/bsub
|
||||
${HPCSTAT_SSH_BINDIR}/hpcstat login
|
||||
if [ "$?" -ne 0 ]; then
|
||||
|
||||
@@ -3,12 +3,13 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDWAfyfDFctbzJTiuK9IPw3yFLqt7vqd/T0/HoZfH/b
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDJ/jzUQ6QuAjnAryvpWk7TReS6pnHxhEXY9RonojKkurhfYSQO/IlxDMDq23TFXcgu8iZG4cS6MADgx/KNZD/MjuN9YNCIEGvMwzWvB0oM25BC6Vf3iKDmhH06rZKH6/g5GN+HWoCN4yE/+MhIpegFO3+YMpveXwEESlyoIjPvcW+RwmlNJevrHd83ETYDQ4AybWyJo6en5tz2ngr22HaK4MtxgrqnIN/KorY+nrzTNa7VBC7BaZc1tA5FLwUeCXtuzp2ibfrxoGUAiDig4FW09ijCk3Y77y7aNVI2nw5y28nCV5rgVMh5fejtNVqIqku7p+8qgjxvY6veATG0lYgZgw2ldnDGDNbEGxcCnKKmCgZMxok8zTRsniZ91KuHkcl2L7xUo7kdQYzBRwZyQ53eW+yPoqUya4yn272rscBEUMyZzmegfr1SXMqw/8zn+MZdr1KXEvrbfjX+2QL52GY3bfYUf3KFje+Sp88k688bRH0vrxj9BCOS7ovbyfe9BEU= xll@xmupc1
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCtnVhZQsJfbs2w9hFZkx4qDhIs++7no+6r5TifP3Dq7epJYd2QYx4dI66XxTNhKxZjN6a4Xn5nFlYLtQJXOvzBLC8IBf1W5GCH0k/jqzzskS0/Ix/70HzcBwJk8ihWDkyON5Ki1BRCx34RNxth1BIxWyc5QT+lou+D92x8iAu/uOvmcAL3Ua0OlZwxw03hLp/PpS4ZnUqFjc2JVtarY7eQu/i3RwOZUaK6nT2EL8RObzk4xnieqsU5PWwA3voVjetqZaDQ+P7dimQXz/FaucroKxCNyTiy1oG4fdQpm2UDrH6ZfPvdQLYrtet6FQabXOxhV7MuR3jYtxZjs1kDVZIseIZ6IwjetaUoMxvIouRfYjOSIEo9Ek9o0+Yhku4r0uWmPDrymWugU1raMmlRxSUwdlzW+C7mQwtGbs/MG4MN4GWkM6id5DKlY2vYKUfrTzmhY1swCtzKq20fjvyX8qhJdcytgVlOrBZnPje6Qd55sI0RjdgJrBsxT2SYquez7U8= yjq@xmupc1
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDn1pfGen7kjPTHsbb8AgrUJWOeFPHK5S4M97Lcj3tvdcjZi2SXN6PwHQfh8/xGhZbTLPz/40S9O9/Dn30xkUTfnONirKt790jp7VEbOtPnjQPOd/KRNWlS3VV0BELuq5p633Mi13rP6JZtdKmU2uSkvvaUBfCppy3JaWv/B7HLJ48f8IzkdiT1px3dN1eQ4SFoHOiVG0ci5TGG6wfMdoAAnM9R1aXI4gDxnYjLYujpaNZ4hBOta/6ZK/PV0JufoXdIAZjubgk1Hv04XHXLR2Z0UhRM6x7UrZIOdM/LlnKmcVk408ZKEj/9m1xRyDsNoZ24CF++cmnwfBHrp9I5nvDI7xOTdZlOhzkiiPM3f4i6s2Qjdv4vpZ6AeE3Qt1LVQyAr67b4UMjHuYqSi2KgyCO6My2Ov2eRoS74EKcb8ejJv3O+XInmYUgDgTgDFT3CgQgK2DG45HiV6nOkaE/6iKx2JSOiYZTFc7TRcePfXF9JQD7dXFde6qm3EbIVyJIpCJ8= zem@xmupc1
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCW2fx1Sim7X2i/e/RBPEl1q/XbV7wa9pmZfnRINHIv24MCUgtNZ5GHEEW7dvzrQBeRj3I7CAyK8fbuhv/l8HuDtjxJJ1fmcBp9UG5vfpb/UTxayJxHBRrwokp2JL7HKVviI6d8FcNa/T0CMoUNYXnel6dE3B78k9Q0dDxlOGS1MzgsP3Pn66lm0ww9FRAVHe+KkhFmwyQ1VHUxHgK4QjCIt7+9+PJE7fK0aVWBsR309pui7Pbm6mgd4d6mwiBeVvxsNGnI4DsO1hz4N2GapuQy19PDiG7A4H41Z5RYQnv/3XTy4TBXOFQm77v6pyGkCmG6BGnRdvMB6C0hWPJvudbsA/BNp4ApL7/CrwTdLp1z6ToAOLvKrUQAM+hcbJimnFVMXqz7iSYg99XTnzue7ncecp19XiaDJbM47bGXcT4nTO5XaiMYi2xGAHIrij5GIuFF5ymKYSp5ejb1VucMdKlaaAmS10+wdUcuT7tzX/IuVr5aqg2dsxT5aJCRhZ1k2V0= xly@xmuhpc
|
||||
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCmJoiGO5YD3lbbIOJ99Al2xxm6QS9q+dTCTtlALjYI5f9ICGZJT8PEGlV9BBNCRQdgb3i2LBzQi90Tq1oG6/PcTV3Mto2TawLz5+2+ym29eIq1QIhVTLmZskK815FpawWqxY6+xpGU3vP1WjrFBbhGtl+CCaN+P2TWNkrR8FjG2144hdAlFfEEqfQC+TXbsyJCYoExuxGDJo8ae0JGbz9w1A1UbjnHwKnoxvirTFEbw9IHJIcTdUwuQKOrwydboCOqeaHt74+BnnCOZhpYqMDacrknHITN4GfFFzbs6FsE8NAwFk6yvkNXXzoe60iveNXtCIYuWjG517LQgHAC5BdaPgqzYNg+eqSul72e+jjRs+KDioNqvprw+TcBBO1lXZ2VQFyWyAdV2Foyaz3Wk5qYlOpX/9JLEp6H3cU0XCFR25FdXmjQ4oXN1QEe+2akV8MQ9cWhFhDcbY8Q1EiMWpBVC1xbt4FwE8VCTByZOZsQ0wPVe/vkjANOo+brS3tsR18= 00@xmuhpc
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCxcIWDQxVyIRqCGR4uWtrh4tLc025+q6du2GVsox8IzmBFkjNY8Au5GIMP5BKRstxFdg3f/wam8krckUN9rv5+OHB9U8HGz77Xs0FktqRVNMaDPdptePZQJ9A9eW3kkFDfQnORJtiVcEWfUBS3pi0QFOHylnG27YyC/Vjx9tjvtJWKsQEVTFJbFHPdi+G7lHTpqIGx+/a2JN9O6uVujXXYvjSVXsd+CWB9VMZMvYCIz2Ecb6RqR3brj4FhRRl8zyCj+J4ACYFdGWL98fTab2uPHbpVeKrefFFA43JOD/4zwBx/uw7MAQAq0GunTV3FpBfIAQHWgftf2fSlbz20oPjCwdYn9ZuGJOBUroryex7AKZmnSYM3biLHcctQfZtxqVPEU3W/62MUsI/kZb9RcF24JRksMoS2XWTiv2HFf5ijQGLXXOjqiTlGncwiKf65DwkDBsSxzgbXk5Uo86viq6UITFXPx/RytU+SUiN4Wb7wcBTjt/+tyQd1uqc7+3DCDXk= 01@xmuhpc
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDkT/P4MnzxBh8sRi0oQ88duNpY/ejFtptGqUQJVobj23vbu7ju6x/yuXqnHFOLi/IOZgNl5oBhRlJekRL+FWMIwpPBA6MnbVNkHXvwu5kLXVTt0O9dhJfDiPPbYcNjOhw4o8aZMc0oEyz8xZgkPoIehHQda+K5vRhFnYCRgn2X92VY/dW1QqPJKEfN47Tsp00w8wyKixEvuJe8OBEoKDpiZYzbXJKuoKhCdMp0uMHMCojYuYP9rGZO6bHl7Q6cYotGx1jH2pe30Ujtm3Xbm44H1mhXr1K/lhcHfojSge8POqii+eaXSCzqRlXaWyvrL9JLaaRD7GfWDaRWSKDfN8Ha4mnUvRtObRMSLOnr2QOTLJw9QPnlDDxCd1q7yluKraccYnTQQP5JuBwkRqjuJTatd9b18Z14HffmXZNR7asT1sJXK1rWKeLTrZwqxpkuwLAnbr60PVwfMHZeZ6FVPXGZ4wQb22lFHvaZZCEJf+9QDXpDn5L59FlaBYO2Xwojj3s= 02@xmuhpc
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDOF3LfnQiI8wpsXGn87bt7rbUZcgsdaOSOswk4Vf4dBautEdQZc0q+UDB2TlR2K8L7SPyywpl5z67euN5QRJLEwg8flTybiJp3EKDctYEM22sa36ONcSIJ/iHSdCkwtPXkBYreh9e+MAHfTroIKK5zM/P1QIN3NrknIXpWjLDF73ejrxE+EXRK6jbuWfo+5dnLnDoUFt1e+pYLZos5KRRB94Qt5I79D/cAg3hG+Zl2FCCOpn1hIdLo/kWJTKUPe61oUaIxriV6nCXp/pU1BHlM43hGowiHa4bVZIs8Eo4r7OI9thhSuS2BKSifibBKIicZtntSlS/I3xa5am28YLmrOiEXRsjPom7trO8qIhPfYOc/yFDg1gcpLxyNroCPooPBzPxUqrTT96Q4fDDTaqfyuVxQFxbYoFAqQs8/lw6WcGJ4fGC5JPsPiwoSdQy/B7gCfQcFjPXp1NH8Sx+xMLCmxRqdKSyeiEwoyB0tZ6ngaI73HFhCPX1/rLx3xv0zd/8= 03@xmuhpc
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC96jp6qFrWt4651Arg+Ua6AU3CjftZuounKLlZ8s268Lo9Cba+nmoOGRNzefqr+f6/7KmFKd9+jqS3ZnKFQbzRFVzzHHIT7tSlgxFRw+yb553/vgm7z6d0HGd3B7XjpIpR7DrM/unnXtiT/WuX+UIKKQ1S4kHp4fTJxZuwzYgNWDsT7O/5H7nBoRVuUSG/achCzTq5V5WfNjvrGZypCmcCw5MTH3Iab4qQ7fhRK46e/OpgSMmsY1ZuEynIwVtimW4G10MUWZdawN4LHBNsCDBmBu0H1DYBb9AUW5IuifAyFPPlTOPtuzpEganaMwotcXiAwhfPQg1c0TfbB4ZJPow612dzxcflHAJyFy2LXbiG0rF48h0GpW5gY92QkeMQcbybKOS5yVlXynNNg0nL1bx+reu7Fy4jurc0facTaqzpSiyXsBLSOva+DZrxl2MBDLEdykkQMNIY69GeeC2XIN4tbfGDYU8VVtwnXJUkmeHAge5ypI1kkPhYRDxPDspym9M= 04@xmuhpc
|
||||
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9FmT0i2j9JsnyeVrEZP8gaWHnc5NnhJgb1sP8MP/pjx/GMEkms2LQvZYNw8MQvGA6HH/O2acy5NIdD69QkRlALXZlWpUQco8JDuJe7+2xkTMGPOAqB5YLMHRpFGHUmDMuSFGSg2YyLXaWXoWmib5xAvTL95xAcdNgp5xqWvO2N55edDeVOY5cTmIE2vC0nm5JSjMEMcIuqL8yJ3AweN4JkD8CVVy3po8f+krKsaYB+f21MqqSnCQ/cpKlWHuMN9k85hP/FB1E7gBXW/MuZ1uOm4IzjBhj8tYVN0UY7Mo2/9PhFqoBKGr6vs7Nx1mXBJ/A1lIKvW+ROvQ9ADpOfww6kPuHbX16gQ55JG7zneWeiP5pVaI4YZ4O1vAvARw/SaSFhRdpymPs5r+wdIDV9gGoqORrYqoPBz7Q02V71W+EV7WFAgxiJozO0vZwD9JJ2zivyIJfcVtIOMIvEhfsha7Hviut4JIOyoaEHjIZYsmvYHEeEBA4pTUHIUZlZj/St7U= 05@xmuhpc
|
||||
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJRWge2+B1Et03n/B4ALBcAnjvtWPPmcFAoIlLP8oFkB hpcstat
|
||||
|
||||
@@ -46,7 +46,6 @@ inputs:
|
||||
nixpkgs.march = "silvermont";
|
||||
nix.substituters = [ "https://cache.nixos.org/" "https://nix-store.chn.moe" ];
|
||||
networking = { hostname = "nas"; networkd = {}; };
|
||||
kernel.variant = "xanmod-latest";
|
||||
};
|
||||
hardware = { cpus = [ "intel" ]; gpu.type = "intel"; };
|
||||
services =
|
||||
@@ -54,7 +53,7 @@ inputs:
|
||||
snapper.enable = true;
|
||||
samba = { enable = true; hostsAllowed = "192.168. 127."; shares = { home.path = "/home"; root.path = "/"; }; };
|
||||
sshd = {};
|
||||
xray.client.dnsmasq.hosts."git.nas.chn.moe" = "127.0.0.1";
|
||||
xray.client = { enable = true; dnsmasq.hosts."git.nas.chn.moe" = "127.0.0.1"; };
|
||||
groupshare = {};
|
||||
smartd.enable = true;
|
||||
beesd.instances =
|
||||
|
||||
@@ -55,18 +55,27 @@ inputs:
|
||||
};
|
||||
nixpkgs =
|
||||
{ march = "znver4"; cuda = { enable = true; capabilities = [ "8.9" ]; forwardCompat = false; }; };
|
||||
kernel.patches = [ "cjktty" "hibernate-progress" ];
|
||||
kernel = { variant = "cachyos"; patches = [ "cjktty" "hibernate-progress" ]; };
|
||||
networking.hostname = "pc";
|
||||
sysctl.laptop-mode = 5;
|
||||
gui.enable = true;
|
||||
};
|
||||
hardware = { cpus = [ "amd" ]; gpu = { type = "nvidia"; dynamicBoost = true; }; legion = {}; };
|
||||
hardware =
|
||||
{
|
||||
cpus = [ "amd" ];
|
||||
gpu =
|
||||
{
|
||||
type = "amd+nvidia";
|
||||
nvidia = { prime.busId = { amd = "6:0:0"; nvidia = "1:0:0"; }; dynamicBoost = true; driver = "beta"; };
|
||||
};
|
||||
legion = {};
|
||||
};
|
||||
packages.packageSet = "workstation";
|
||||
virtualization =
|
||||
{
|
||||
waydroid.enable = true;
|
||||
docker.enable = true;
|
||||
kvmHost = { enable = true; gui = true; autoSuspend = [ "win10" "hardconnect" ]; };
|
||||
kvmHost = { enable = true; gui = true; };
|
||||
nspawn = [ "arch" "ubuntu-22.04" "fedora" ];
|
||||
};
|
||||
services =
|
||||
@@ -88,6 +97,7 @@ inputs:
|
||||
sshd = {};
|
||||
xray.client =
|
||||
{
|
||||
enable = true;
|
||||
dnsmasq.hosts = builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
@@ -121,31 +131,50 @@ inputs:
|
||||
publicKey = "l1gFSDCeBxyf/BipXNvoEvVvLqPgdil84nmr5q6+EEw=";
|
||||
wireguardIp = "192.168.83.3";
|
||||
};
|
||||
gamemode = { enable = true; drmDevice = 0; };
|
||||
slurm = { enable = true; cpu = { cores = 16; threads = 2; }; memoryMB = 90112; gpus."4060" = 1; };
|
||||
gamemode = { enable = true; drmDevice = 1; };
|
||||
slurm =
|
||||
{
|
||||
enable = true;
|
||||
cpu = { cores = 16; threads = 2; mpiThreads = 2; openmpThreads = 4; };
|
||||
memoryMB = 90112;
|
||||
gpus."4060" = 1;
|
||||
};
|
||||
xrdp = { enable = true; hostname = [ "pc.chn.moe" ]; };
|
||||
};
|
||||
bugs = [ "xmunet" "backlight" "amdpstate" "suspend-hibernate-no-platform" ];
|
||||
user.users = [ "chn" "test" ];
|
||||
bugs = [ "xmunet" "backlight" "amdpstate" ];
|
||||
};
|
||||
system.nixos.tags = [ "next" ];
|
||||
boot.kernelParams =
|
||||
[
|
||||
"acpi_osi=!" ''acpi_osi="Windows 2015"''
|
||||
"mt7921e.disable_aspm=y" # 避免休眠恢复后无 wifi,似乎有时还是有问题
|
||||
"amdgpu.sg_display=0" # 混合模式下避免外接屏幕闪烁,和内置外接屏幕延迟
|
||||
"acpi.ec_no_wakeup" # 睡眠时避免开盖唤醒,似乎没有用
|
||||
];
|
||||
# 禁止鼠标等在睡眠时唤醒
|
||||
services.udev.extraRules = ''ACTION=="add", ATTR{power/wakeup}="disabled"'';
|
||||
networking.extraHosts = "74.211.99.69 mirism.one beta.mirism.one ng01.mirism.one";
|
||||
services.colord.enable = true;
|
||||
environment.persistence."/nix/archive" =
|
||||
{
|
||||
hideMounts = true;
|
||||
users.chn.directories = builtins.map
|
||||
(dir: { directory = "repo/${dir}"; user = "chn"; group = "chn"; mode = "0755"; })
|
||||
[ "lammps-SiC" "BPD-paper" "kurumi-asmr" "linwei-stuff" "BPD-paper-old" ];
|
||||
};
|
||||
specialisation =
|
||||
{
|
||||
hybrid.configuration =
|
||||
nvidia.configuration =
|
||||
{
|
||||
nixos =
|
||||
{
|
||||
hardware.gpu =
|
||||
{ type = inputs.lib.mkForce "amd+nvidia"; prime.busId = { amd = "6:0:0"; nvidia = "1:0:0"; }; };
|
||||
services.gamemode.drmDevice = inputs.lib.mkForce 1;
|
||||
hardware.gpu.type = inputs.lib.mkForce "nvidia";
|
||||
services.gamemode.drmDevice = inputs.lib.mkForce 0;
|
||||
};
|
||||
system.nixos.tags = [ "hybrid" ];
|
||||
system.nixos.tags = [ "nvidia" ];
|
||||
};
|
||||
xanmod.configuration =
|
||||
{
|
||||
nixos.system.kernel.variant = "xanmod-latest";
|
||||
nixos.system.kernel.variant = inputs.lib.mkForce "xanmod-latest";
|
||||
system.nixos.tags = [ "xanmod" ];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -20,6 +20,7 @@ inputs:
|
||||
networking = { hostname = "pcarm"; networkd = {}; };
|
||||
nixpkgs.arch = "aarch64";
|
||||
kernel.variant = "nixos";
|
||||
sops.enable = false;
|
||||
};
|
||||
services.sshd = {};
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ inputs:
|
||||
{
|
||||
# snapper.enable = true;
|
||||
sshd = {};
|
||||
xray.client = {};
|
||||
xray.client.enable = true;
|
||||
fail2ban = {};
|
||||
wireguard =
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ inputs:
|
||||
{
|
||||
snapper.enable = true;
|
||||
sshd = {};
|
||||
xray.client = {};
|
||||
xray.client.enable = true;
|
||||
firewall.trustedInterfaces = [ "virbr0" ];
|
||||
wireguard =
|
||||
{
|
||||
@@ -55,7 +55,6 @@ inputs:
|
||||
};
|
||||
bugs = [ "xmunet" "suspend-hibernate-no-platform" ];
|
||||
};
|
||||
boot.kernelParams = [ "intel_iommu=off" ];
|
||||
environment.systemPackages = with inputs.pkgs; [ maliit-keyboard maliit-framework ];
|
||||
powerManagement.resumeCommands = ''${inputs.pkgs.systemd}/bin/systemctl restart iptsd'';
|
||||
services.iptsd.config =
|
||||
|
||||
@@ -24,6 +24,7 @@ inputs:
|
||||
nix.substituters = [ "https://cache.nixos.org/" "https://nix-store.chn.moe" ];
|
||||
initrd.sshd.enable = true;
|
||||
networking = { hostname = "vps4"; networkd = {}; };
|
||||
kernel.variant = "cachyos-server";
|
||||
};
|
||||
services =
|
||||
{
|
||||
|
||||
@@ -30,12 +30,13 @@ inputs:
|
||||
nix.substituters = [ "https://cache.nixos.org/" "https://nix-store.chn.moe" ];
|
||||
initrd.sshd.enable = true;
|
||||
networking = { hostname = "vps6"; networkd = {}; };
|
||||
# do not use cachyos kernel, beesd + cachyos kernel + heavy io = system freeze, not sure why
|
||||
};
|
||||
services =
|
||||
{
|
||||
snapper.enable = true;
|
||||
sshd = {};
|
||||
xray.server = { serverName = "vps6.xserver.chn.moe"; userNumber = 18; };
|
||||
xray.server = { serverName = "vps6.xserver.chn.moe"; userNumber = 20; };
|
||||
frpServer = { enable = true; serverName = "frp.chn.moe"; };
|
||||
nginx =
|
||||
{
|
||||
|
||||
@@ -40,6 +40,10 @@ xray-server:
|
||||
user16: ENC[AES256_GCM,data:fo6KJXlPDn7+FmxjEJQo9d79rDYemLFx6LanYZcJpKJR7Gxq,iv:yEUKPNZ9idrSqyVO9fhksP/7bjPMT/LzNK2VSq503/c=,tag:M87D44SIo9JzDB3ZyKu7fA==,type:str]
|
||||
#ENC[AES256_GCM,data:/Kec+CdtnT11EA==,iv:DnmbWfgriaE6XAnMqq2UXhHhN+Rd/3YRodKVUCJo6p4=,tag:NimqZpbslKxwzoljaZqEdw==,type:comment]
|
||||
user17: ENC[AES256_GCM,data:gQInIcNFxJuCSsMDGq4yTp5JdMMmJRy1tY3PGLoLuuIXWV0a,iv:ya4n9Z7T9/bxeHqi5QqwJprEzDMsT6X0BuEXRS67wWk=,tag:RcjQfAHv8uc3PgN5c4bySA==,type:str]
|
||||
#ENC[AES256_GCM,data:h7E4P6BiGjktYg==,iv:DhkK3NNppBqo3sXt9U7kbgfaBPYcSEX2hu6VOAesDiE=,tag:XoVbZklwCmU1EBhv0ujcSw==,type:comment]
|
||||
user18: ENC[AES256_GCM,data:dssxPEv8srXydunolaaDAYYo+BOXhp2PoqidOWH3z6NYBpyB,iv:WCLcMMwQJiHZBwreQpaOZp2saXvjBwgYUqSf7HQhMgA=,tag:5jsAVcgAgO+7JhBINz6tzQ==,type:str]
|
||||
#ENC[AES256_GCM,data:qGsMmWrUIzVdHw==,iv:DXayEA5zquwOzm+TqECYNHM98r0WSzcP3gA8zkzdPy4=,tag:OKTx12RqP9VxJQOnrBLkmw==,type:comment]
|
||||
user19: ENC[AES256_GCM,data:+Mh15DR9xvFAwks86iuHEA9FpObKWTSuVOEzUDpBUS/h0hOz,iv:zYIkic2bibvwCBpomnJ9465mda1rbm3RERBZY9twXuc=,tag:bwdL6DAGgkGYhYFI2C4A+A==,type:str]
|
||||
private-key: ENC[AES256_GCM,data:ts/LRGFAsYqvGvkvlxUI42IW1a8cGsSkpZhMDd3QVceRKvhPb1SRDaXoSw==,iv:6xX9xFIFUNlLBZ6CPBOz9JbHpvC4+QG9ZaCZcWdl12c=,tag:DYIa+QTV8vyl1l7OKKykTw==,type:str]
|
||||
nginx:
|
||||
#ENC[AES256_GCM,data:85LrqdTMIhSa,iv:mIQPYz8VPd5AxeMCQEdTGMD0Iqa5QEAa5+8JVFaj3JM=,tag:TcZd7S3WRPpEV9lHI1fzbw==,type:comment]
|
||||
@@ -83,8 +87,8 @@ sops:
|
||||
ZXFTU3ZCaW1pTVh0RUJzdDdGdHlPYTgK2mlgcX2kEc8+2UDdBnhUm6IIuh8V6agW
|
||||
ooxH9OEPXUVI/4JcDo4v8ZUhAyU1ehLH0Ef7PJCChOZe2KZmWSNbhA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2024-05-25T09:01:19Z"
|
||||
mac: ENC[AES256_GCM,data:xYK5VTYHwryDcH0fhnezn5aYQ+XAPAJ7PIrL1ygKw3F/rAwRQlWk0/zmqypmpqbPX4mAJKzDfgoTNh8iUtF8ehmfOS+7OPUTuKVRvPI39HfcJbRN3/oOdN40AXSa5cZjgKrAGdhWvwyw0WdDMkRfwJztAR5Jj0dKzZ5THW+5zSs=,iv:Y5UUe1I95ltiVcUPBUcmIpnKHFfAlQmcF8ZlxZht1i4=,tag:3mA/epV254+P7WkkuhDOqg==,type:str]
|
||||
lastmodified: "2024-06-30T10:43:57Z"
|
||||
mac: ENC[AES256_GCM,data:Mg/DZghIkaWM5KEjk5zg3S0L5qPa8/rkc2ooSjA1ewzbDhTKls2tzv7fQqLx2WQtcJiKkoVx22UkiL0AzBwJdCr3473vx93ajTVK9HNu3jqXmuzSiv2iVS21EX9tyBNiL6uWlVAtlVfMMs69PEUF+EJIYY5TkVVPaQjzEebwo5w=,iv:tFON7RVSnNNHo5U4dRuMGDhH5iPGShW9uoda+apiIjI=,tag:3nG/u7vaChFBHoDsLLb23w==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.8.1
|
||||
|
||||
@@ -30,6 +30,7 @@ inputs:
|
||||
nix.substituters = [ "https://cache.nixos.org/" "https://nix-store.chn.moe" ];
|
||||
initrd.sshd.enable = true;
|
||||
networking = { hostname = "vps7"; networkd = {}; };
|
||||
kernel.variant = "cachyos-server";
|
||||
};
|
||||
services =
|
||||
{
|
||||
@@ -45,9 +46,9 @@ inputs:
|
||||
matrix = { port = 8009; redisPort = 6380; slidingSyncPort = 9001; };
|
||||
};
|
||||
vaultwarden.enable = true;
|
||||
beesd.instances.root = { device = "/"; hashTableSizeMB = 1024; };
|
||||
beesd.instances.root = { device = "/"; hashTableSizeMB = 1024; loadAverage = 4; };
|
||||
photoprism.enable = true;
|
||||
nextcloud.enable = true;
|
||||
nextcloud = {};
|
||||
freshrss.enable = true;
|
||||
send.enable = true;
|
||||
huginn.enable = true;
|
||||
@@ -67,6 +68,7 @@ inputs:
|
||||
};
|
||||
vikunja.enable = true;
|
||||
chatgpt = {};
|
||||
xray.server = { serverName = "xserver.vps7.chn.moe"; userNumber = 4; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -108,6 +108,17 @@ chatgpt:
|
||||
telegram:
|
||||
token: ENC[AES256_GCM,data:Mr6KrAzYoDXA+dPT3oXqK2wm9ahTjZ5GVE/iRPsmcM+S2MABT+8ramyHz9oIFw==,iv:nIZ8rpSxz2GwMbDQFfG3xauMQjiriZ1oxFMrEQeH7sQ=,tag:y5U1T1vV/mmdE/CeaeTR8g==,type:str]
|
||||
chat: ENC[AES256_GCM,data:8w/0EI64a1dC,iv:dHu9JHcUY7QPd9YBKXnrRXQB2K6jpnLrSFs+1IJmkio=,tag:3ucN3uNnBxxRF+cbLsa1nQ==,type:str]
|
||||
xray-server:
|
||||
clients:
|
||||
#ENC[AES256_GCM,data:aAZS,iv:Z+iJG7yC6HJeNdKCCpsZSc9Ny7kAt6GYfXUtZozMb4A=,tag:iMfwjqqmLvu5a8YpF7a0zQ==,type:comment]
|
||||
user0: ENC[AES256_GCM,data:Q8MFrN/3SRgzSlwTx2GmpP/gvG1vpYiVgjsESzUoomsJaigP,iv:oLsf7AX3FE0tFOkJAbqrZVrCa6UxKjp450Sl1rs2Vs0=,tag:5w+AX0p4Or1GAQsEU3NxOQ==,type:str]
|
||||
#ENC[AES256_GCM,data:j3zVwqHmag==,iv:8+ol60wNlbV2RzMBe47VxIrZuec8aXDUNcQvHcxKuiA=,tag:1AgCMfZf9vzWiWDS6hkw2Q==,type:comment]
|
||||
user1: ENC[AES256_GCM,data:ucCiL7uoSafFUP9IiwKOjJqgwNxNLmuHxYXsLYl0fBgbCT3F,iv:RbNPwvSWibODQqySRc+YW65nUvRwaeXT0eDh02sfrwM=,tag:iE7GGrkBxljBT9HdPzDOfA==,type:str]
|
||||
#ENC[AES256_GCM,data:x7dwVDe22M8=,iv:+fT7VUxZGd8SgS0PnEBqHLPLDuywu4s01iWB6TA/BKQ=,tag:CxfP7xSd4L9RBulSfViHaQ==,type:comment]
|
||||
user2: ENC[AES256_GCM,data:e6PbRg30dzOJSXNmU6TML4AaFsSWEvZwN7MHAEX6fEW2p3hW,iv:Y+YYAO6hY9e/T8LSCr34M7riGmSzFIocmWwAwWjnZQs=,tag:LTkdGcRyrx7HqvbSYSsv4A==,type:str]
|
||||
#ENC[AES256_GCM,data:j83rYg==,iv:3oEdAoVz7aMcezcy2chTO0LQTtKpTrJJoQZx3PC03BU=,tag:ABteEIyr2Y6MbGQhmrQySQ==,type:comment]
|
||||
user3: ENC[AES256_GCM,data:Uk0Ax9FVzmmYs+ggWy7z6FEkuj2tppGlvnQdoW6PDI1VA9oI,iv:wSxigXleRUalQR1/TzKfdUVrdyEUuq+Wg42gSv1QMAI=,tag:qn6nBWv6MlGhMarCfI13BA==,type:str]
|
||||
private-key: ENC[AES256_GCM,data:TarrinCFzWkB5zCc7i7f3B3tFfxrF+cGnrg4bw9CAGKWBazSJHCviY8Imw==,iv:azHdrc6AlgS9RPwGVsYRb8bBeC/askCdut1rnv9TA3I=,tag:AT2lLraKVgbp9GmlLJiI+w==,type:str]
|
||||
sops:
|
||||
kms: []
|
||||
gcp_kms: []
|
||||
@@ -132,8 +143,8 @@ sops:
|
||||
SnFHS1Z0SXUzTFdEd29KTy9DU3Y3R0UKfhh+rUmWDrf+UGjclP57dHipPLFoXSqy
|
||||
HdelmfV6q4/c7ppx2E+oZw3VNgoZCsrxxzYZfwxHJiZb+5vkE0D8iA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2024-05-10T08:51:41Z"
|
||||
mac: ENC[AES256_GCM,data:JQGv8hKLp0XFj5se+dKGs8r+qjEnlxXNMBlMk3Cv/c/b96nyreKva95DyR9JdY4ND8emY00IAIefnzT+uMvpmxXO/ttM8Vf2xPus6jBKp5omSjr0mbwBcUz9+oXWElua6LJKL/3v1NZ7t/usH9KCWeAnjtaNi/6T4U0z3IY6a9U=,iv:SadPtZGKqHS+ZTp09kR9gs8OyIr2lcywRxyPTfsqL6A=,tag:itZBK6Dde5212d+OBTKb9A==,type:str]
|
||||
lastmodified: "2024-06-08T09:15:52Z"
|
||||
mac: ENC[AES256_GCM,data:EY6sFc4EcTuxPgIZQ51HFZZZf+khb7mkNEvb6U12kCtoJAEo+i83uszwBZCo/QWw6VCCt9c//9y0mNH4FjZPJAxweJHcRtanyTXa5jdyv12qINUceYe7Uhcb7JuiiEns9DEbrr3UeAKfbPC+N5mD/2trzht0E8hqnFlWU/fysz8=,iv:saymdP4nFveEWx0JrBR2bW8SUl6xCJKhYqw+CsrfRG8=,tag:CHGvJAO8hpSMNdU2YE2OGw==,type:str]
|
||||
pgp: []
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.8.1
|
||||
|
||||
@@ -16,10 +16,25 @@ SLURM 是一个用来对任务排队的系统,轮到某个任务时,再调
|
||||
|
||||
## 常用命令
|
||||
|
||||
我做了一个 TUI 界面,用起来比较简单,大多情况下可以满足需求。命令为:
|
||||
|
||||
```bash
|
||||
sbatch-tui
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```bash
|
||||
sbatch
|
||||
```
|
||||
|
||||
如果需要在提交任务时指定更详细的细节,或者要编写脚本批量提交任务,则在 `sbatch` 后面加上参数,这时是直接调用来自 SLURM 的 `sbatch` 命令。
|
||||
常用的参数见下文。更详细的内容见 SLURM 的官方文档。
|
||||
|
||||
提交一个 VASP GPU 任务的例子:
|
||||
|
||||
```bash
|
||||
sbatch --gpus=1 --ntasks-per-gpu=1 --job-name="my great job" vasp-nvidia-640
|
||||
sbatch --gpus=1 --ntasks-per-gpu=1 --job-name="my great job" vasp-nvidia
|
||||
```
|
||||
|
||||
* `--gpus` 指定使用GPU 的情况:
|
||||
@@ -30,12 +45,12 @@ sbatch --gpus=1 --ntasks-per-gpu=1 --job-name="my great job" vasp-nvidia-640
|
||||
* `--ntasks-per-gpu=1` 对于 VASP 来说一定要写。
|
||||
* `--job-name=xxx` 指定任务的名字。可以简写为 `-J`。也可以不指定。
|
||||
* 默认情况下,一个 task 会搭配分配一个 CPU 核(一个线程),一般已经够用。如果一定要修改,用 `--cpus-per-task`。
|
||||
* `vasp-nvidia-640` 指调用 std 版本,要使用 gam 或 ncl 版本时,写为例如 `vasp-nvidia-640-gam`。
|
||||
* `vasp-nvidia` 指调用 std 版本,要使用 gam 或 ncl 版本时,写为例如 `vasp-nvidia-gam`。
|
||||
|
||||
提交一个 VASP CPU 任务的例子:
|
||||
|
||||
```bash
|
||||
sbatch --ntasks=4 --cpus-per-task=4 --hint=nomultithread --job-name="my great job" vasp-intel-640
|
||||
sbatch --ntasks=4 --cpus-per-task=4 --hint=nomultithread --job-name="my great job" vasp-intel
|
||||
```
|
||||
|
||||
* `--ntasks=4 --cpus-per-task=4` 指定使用占用多少核。
|
||||
@@ -45,7 +60,7 @@ sbatch --ntasks=4 --cpus-per-task=4 --hint=nomultithread --job-name="my great jo
|
||||
* 对于 xmupc2:`--ntasks=4 --cpus-per-task=10`。
|
||||
* `--hint=nomultithread` 记得写。
|
||||
* `--job-name=xxx` 指定任务的名字。可以简写为 `-J`。也可以不指定。
|
||||
* `vasp-intel-640` 指调用 std 版本,要使用 gam 或 ncl 版本时,写为例如 `vasp-intel-640-gam`。
|
||||
* `vasp-intel` 指调用 std 版本,要使用 gam 或 ncl 版本时,写为例如 `vasp-intel-gam`。
|
||||
|
||||
要把其它程序提交到队列里,也是类似的写法。请自行举一反三。
|
||||
|
||||
@@ -186,7 +201,6 @@ samba 就是 windows 共享文件夹的那个协议。
|
||||
|
||||
VASP 有很多很多个版本,具体来说:
|
||||
|
||||
* VASP 多个版本可以共存,但为了简单只安装了 6.4.0 版本。
|
||||
* VASP 可以用不同的编译器编译。目前安装的有:nvidia、intel。nvidia 使用 GPU 计算,intel 能用 CPU 计算。其它版本性能不佳,没有安装。
|
||||
* VASP 的 std/gam/ncl 版本有一点区别,一般用 std,只有一个 gamma 点的时候用 gam 会快一点,系统中存在方向不平行的磁矩时必须用 ncl。
|
||||
* 无论哪个版本,都集成了下面这些补丁:
|
||||
@@ -199,14 +213,14 @@ VASP 有很多很多个版本,具体来说:
|
||||
如何提交 VASP 到队列系统已经在上面介绍过了。下面的例子是,如果要直接运行一个任务的写法:
|
||||
|
||||
```bash
|
||||
vasp-nvidia-640-env mpirun -np 1 -x CUDA_DEVICE_ORDER=PCI_BUS_ID -x CUDA_VISIBLE_DEVICES=0 -x OMP_NUM_THREADS=4 vasp-std
|
||||
vasp-intel-640-env mpirun -n 2 -genv OMP_NUM_THREADS=4 vasp-std
|
||||
vasp-nvidia-env mpirun -np 1 -x CUDA_DEVICE_ORDER=PCI_BUS_ID -x CUDA_VISIBLE_DEVICES=0 -x OMP_NUM_THREADS=4 vasp-std
|
||||
vasp-intel-env mpirun -n 2 -genv OMP_NUM_THREADS=4 vasp-std
|
||||
```
|
||||
|
||||
其中 `CUDA_VISIBLE_DEVICES` 用于指定用哪几个显卡计算(多个显卡用逗号分隔)。
|
||||
要查看显卡的编号,可以用 `CUDA_DEVICE_ORDER=PCI_BUS_ID vasp-nvidia-640-env nvaccelinfo` 命令。
|
||||
要查看显卡的编号,可以用 `CUDA_DEVICE_ORDER=PCI_BUS_ID vasp-nvidia-env nvaccelinfo` 命令。
|
||||
|
||||
这里 `vasp-xxx-6.4.0` 命令的作用是,进入一个安装了对应版本的 VASP 的环境,实际上和 VASP 关系不大;
|
||||
这里 `vasp-xxx-env` 命令的作用是,进入一个安装了对应版本的 VASP 的环境,实际上和 VASP 关系不大;
|
||||
后面的 `mpirun xxx` 才是真的调用 VASP。
|
||||
所以实际上你也可以在这个环境里做别的事情,例如执行上面的 `nvaccelinfo` 命令。
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ inputs:
|
||||
{
|
||||
snapper.enable = true;
|
||||
sshd = { passwordAuthentication = true; groupBanner = true; };
|
||||
xray.client = {};
|
||||
xray.client.enable = true;
|
||||
firewall.trustedInterfaces = [ "virbr0" "waydroid0" ];
|
||||
smartd.enable = true;
|
||||
beesd.instances =
|
||||
@@ -76,7 +76,7 @@ inputs:
|
||||
slurm =
|
||||
{
|
||||
enable = true;
|
||||
cpu = { cores = 16; threads = 2; };
|
||||
cpu = { cores = 16; threads = 2; mpiThreads = 3; openmpThreads = 4; };
|
||||
memoryMB = 94208;
|
||||
gpus = { "2080_ti" = 1; "3090" = 1; "4090" = 1; };
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ inputs:
|
||||
{
|
||||
snapper.enable = true;
|
||||
sshd = { passwordAuthentication = true; groupBanner = true; };
|
||||
xray.client = {};
|
||||
xray.client.enable = true;
|
||||
firewall.trustedInterfaces = [ "virbr0" "waydroid0" ];
|
||||
smartd.enable = true;
|
||||
beesd.instances.root = { device = "/"; hashTableSizeMB = 16384; threads = 4; };
|
||||
@@ -66,7 +66,7 @@ inputs:
|
||||
slurm =
|
||||
{
|
||||
enable = true;
|
||||
cpu = { sockets = 2; cores = 22; threads = 2; };
|
||||
cpu = { sockets = 2; cores = 22; threads = 2; mpiThreads = 4; openmpThreads = 10; };
|
||||
memoryMB = 253952;
|
||||
gpus = { "4090" = 1; "p5000" = 1; };
|
||||
};
|
||||
|
||||
282
flake.lock
generated
282
flake.lock
generated
@@ -43,16 +43,17 @@
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711742460,
|
||||
"narHash": "sha256-0O4v6e4a1toxXZ2gf5INhg4WPE5C5T+SVvsBt+45Mcc=",
|
||||
"rev": "4dbdbee45728d8ce5788db6461aaaa89d98081f0",
|
||||
"revCount": 197,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/zhaofengli/attic/0.1.197%2Brev-4dbdbee45728d8ce5788db6461aaaa89d98081f0/018e8bce-1229-7d78-a052-5121272f0341/source.tar.gz"
|
||||
"lastModified": 1717279440,
|
||||
"narHash": "sha256-kH04ReTjxOpQumgWnqy40vvQLSnLGxWP6RF3nq5Esrk=",
|
||||
"owner": "zhaofengli",
|
||||
"repo": "attic",
|
||||
"rev": "717cc95983cdc357bc347d70be20ced21f935843",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/zhaofengli/attic/0.1.%2A.tar.gz"
|
||||
"owner": "zhaofengli",
|
||||
"repo": "attic",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"blurred-wallpaper": {
|
||||
@@ -93,11 +94,11 @@
|
||||
},
|
||||
"catppuccin": {
|
||||
"locked": {
|
||||
"lastModified": 1716337435,
|
||||
"narHash": "sha256-eZqH1vLI9eKL/N5toXxOrQO80G0y4pWZrYCp472YBVQ=",
|
||||
"lastModified": 1717070887,
|
||||
"narHash": "sha256-ZTEMINFqQL+m55kmoDYIKf3i2NGitSkjBnnLu99ezh0=",
|
||||
"owner": "catppuccin",
|
||||
"repo": "nix",
|
||||
"rev": "fea5242c0eacc5efa81be0e36206a62e889dbd82",
|
||||
"rev": "2c7661c9fa26a920b8088300ef87d14179c71a27",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -130,11 +131,11 @@
|
||||
"yafas": "yafas"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716670457,
|
||||
"narHash": "sha256-wfD7maFs6phUd45ewWZo1lPAHluOS+9Z7IfdMFk0LGo=",
|
||||
"lastModified": 1718116047,
|
||||
"narHash": "sha256-wt5smsz3nOV8USu2X1ZCQQXJEr9Zvf08pREx/Tpeoos=",
|
||||
"owner": "chaotic-cx",
|
||||
"repo": "nyx",
|
||||
"rev": "fef678d1e1dbefdfbbf72eb6ef28b534af0bc403",
|
||||
"rev": "1ebc5065368a2d800930eb401ce955b99f876b8b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -241,11 +242,11 @@
|
||||
"rocksdb": "rocksdb"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716588782,
|
||||
"narHash": "sha256-DXJrpcNUkgbsd07fmhq3XmTfybrN6LwSh24lZnvKUSo=",
|
||||
"lastModified": 1718077083,
|
||||
"narHash": "sha256-VxakGnd1Gpjyd3fBu8MDuliWd11lJIjPW2Ev61OAguc=",
|
||||
"owner": "girlbossceo",
|
||||
"repo": "conduwuit",
|
||||
"rev": "f3427afc7fc7a0e67a8c78be24cba898a6bdba2e",
|
||||
"rev": "305dfc3b426e71c69612a2f12dcd255c4d0e8cde",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -278,16 +279,17 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716156051,
|
||||
"narHash": "sha256-TjUX7WWRcrhuUxDHsR8pDR2N7jitqZehgCVSy3kBeS8=",
|
||||
"rev": "7443df1c478947bf96a2e699209f53b2db26209d",
|
||||
"revCount": 571,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/ipetkov/crane/0.17.1/018f92f7-d079-7a6a-8660-4fa94147552e/source.tar.gz"
|
||||
"lastModified": 1718078026,
|
||||
"narHash": "sha256-LbQabH6h86ZzTvDnaZHmMwedRZNB2jYtUQzmoqWQoJ8=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "a3f0c63eed74a516298932b9b1627dd80b9c3892",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/ipetkov/crane/%2A.tar.gz"
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"date": {
|
||||
@@ -389,11 +391,11 @@
|
||||
"eigen": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1716569414,
|
||||
"narHash": "sha256-DlefZOWAfZAV9UCbMeBuBG1pJUeNySqwfY7IxLqzeZQ=",
|
||||
"lastModified": 1717213024,
|
||||
"narHash": "sha256-3Cf/LyVCRlTLSe8TrGK5wpnKXcoGkEENbHmP9zoJliY=",
|
||||
"owner": "libeigen",
|
||||
"repo": "eigen",
|
||||
"rev": "5a9f66fb35d03a4da9ef8976e67a61b30aa16dcf",
|
||||
"rev": "eac6355df2fb3e306a3078a236ddc6d9f19fba03",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
@@ -444,11 +446,11 @@
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716247015,
|
||||
"narHash": "sha256-0m+VR3NKA7OENh0QmWRZcyyaNqU/jXekso8QOxMdRrg=",
|
||||
"lastModified": 1716853897,
|
||||
"narHash": "sha256-vZixjUtN4zQr117r26/Q+0fivtG3AYOc8zKjZPoV/mw=",
|
||||
"owner": "Mic92",
|
||||
"repo": "envfs",
|
||||
"rev": "48b1187e814416d0c93aa54da47d6c73f1838c2e",
|
||||
"rev": "5644572b4567e8ebecae28525f953bcb71fbf481",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -546,16 +548,17 @@
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1714544767,
|
||||
"narHash": "sha256-kF1bX+YFMedf1g0PAJYwGUkzh22JmULtj8Rm4IXAQKs=",
|
||||
"rev": "73124e1356bde9411b163d636b39fe4804b7ca45",
|
||||
"revCount": 1852,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/nix-community/fenix/0.1.1852%2Brev-73124e1356bde9411b163d636b39fe4804b7ca45/018f333a-c195-795f-9e07-b43b47d5391f/source.tar.gz"
|
||||
"lastModified": 1717827974,
|
||||
"narHash": "sha256-ixopuTeTouxqTxfMuzs6IaRttbT8JqRW5C9Q/57WxQw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "ab655c627777ab5f9964652fe23bbb1dfbd687a8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/nix-community/fenix/0.1.%2A.tar.gz"
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
@@ -579,14 +582,15 @@
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"revCount": 57,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/edolstra/flake-compat/%2A.tar.gz"
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_3": {
|
||||
@@ -732,11 +736,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1715865404,
|
||||
"narHash": "sha256-/GJvTdTpuDjNn84j82cU6bXztE0MSkdnTWClUCRub78=",
|
||||
"lastModified": 1717285511,
|
||||
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "8dc45382d5206bd292f9c2768b8058a8fd8311d9",
|
||||
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -750,11 +754,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1715865404,
|
||||
"narHash": "sha256-/GJvTdTpuDjNn84j82cU6bXztE0MSkdnTWClUCRub78=",
|
||||
"lastModified": 1717285511,
|
||||
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "8dc45382d5206bd292f9c2768b8058a8fd8311d9",
|
||||
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -787,14 +791,15 @@
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"revCount": 92,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/numtide/flake-utils/0.1.92%2Brev-b1d9ab70662946ef0850d488da1c9019f3a9752a/018e2ca5-e5a2-7f80-9261-445a8cecd4d7/source.tar.gz"
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/numtide/flake-utils/0.1.%2A.tar.gz"
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
@@ -985,11 +990,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716618639,
|
||||
"narHash": "sha256-H3kcJDVqDmXZ9IfVtqObL3JUx/a0ERn6gWBTn+7vwN4=",
|
||||
"lastModified": 1718081048,
|
||||
"narHash": "sha256-dwKvamucNK8gB6RTTfnBeBbBgjARQgHQph8PdHZoL3s=",
|
||||
"owner": "Jovian-Experiments",
|
||||
"repo": "Jovian-NixOS",
|
||||
"rev": "a358c56a163b3b7d149571e853a8f75b2c1ceb38",
|
||||
"rev": "f27db3a9a8c21a65c1ef50cacca3ef2bfff04cb9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1011,11 +1016,11 @@
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716613888,
|
||||
"narHash": "sha256-XqVX42rCdLffurAJWck3KwPhPhin1INp0gd9wV8ETWc=",
|
||||
"lastModified": 1718103647,
|
||||
"narHash": "sha256-+QNxty2pzIG+P6gHPa2+cV3ZOS4TZcumP+bEubIqMmI=",
|
||||
"owner": "martinvonz",
|
||||
"repo": "jj",
|
||||
"rev": "b0913342b10d24bb230353af2b6f2e8844be7db6",
|
||||
"rev": "556c7291c1948f235789bfaa096e24fbd2e22b43",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1043,11 +1048,11 @@
|
||||
"lepton": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1716113343,
|
||||
"narHash": "sha256-0e4K7mLeBpCGR7Kw4XwmzXNmzLt1KIwbC6nlQljCmaA=",
|
||||
"lastModified": 1717243317,
|
||||
"narHash": "sha256-ISpHO8mR3xD0RricR8UVfQz2e4HiP9eqayhyq6q1vj4=",
|
||||
"owner": "black7375",
|
||||
"repo": "Firefox-UI-Fix",
|
||||
"rev": "1406c3fd7bb4b43bade7962491d3106ae58cf10d",
|
||||
"rev": "811e970678c3d67c10bcecafbc54d09332afba9c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1059,11 +1064,11 @@
|
||||
"liburing": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1716398759,
|
||||
"narHash": "sha256-fDlOR13WmwVgMxGUMQXWSZAoy2VhZ5AfZRPF9qmQjSc=",
|
||||
"lastModified": 1716565485,
|
||||
"narHash": "sha256-4R19aJNQYs6vb0/Hz4bWT56YN1P1DkFL/sxdE4Yj0CE=",
|
||||
"owner": "axboe",
|
||||
"repo": "liburing",
|
||||
"rev": "49be3cad491ae8b3c40348b8d78ae2b0d3726b78",
|
||||
"rev": "b90c0e670a93caabbebe2d9e24ff85cece4cfe0e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1092,11 +1097,11 @@
|
||||
"lmod": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1713046088,
|
||||
"narHash": "sha256-A1mMpYGxAyrplSQo2wfyA6Dy/oTgq5/POfuXmZXs4WE=",
|
||||
"lastModified": 1717349355,
|
||||
"narHash": "sha256-1TEoQ1jC6Lp/TQPNlL1uYKHT1ysK7UrAnaawILWaITA=",
|
||||
"owner": "TACC",
|
||||
"repo": "Lmod",
|
||||
"rev": "7940a1c13383a4527c2e2731eada34b9cfe77157",
|
||||
"rev": "f0e0954b213d13afdd1cdc54e1391eb07d15c977",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1124,11 +1129,11 @@
|
||||
"misskey": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1709515934,
|
||||
"narHash": "sha256-3zMW1Rrv9j/sFENs+vFguRGJtsxKmtl4prvRnd2SBxI=",
|
||||
"lastModified": 1717405331,
|
||||
"narHash": "sha256-NV/H8ah8YKpnzytR4OFKf23TPPlOdyGYesbRZDznAb4=",
|
||||
"ref": "refs/heads/chn-mod",
|
||||
"rev": "00527b3167f07f10a407adb5ad86759449181554",
|
||||
"revCount": 25465,
|
||||
"rev": "93f76cfe6a458915a3980d389d4c1dec3c117aaa",
|
||||
"revCount": 25668,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/CHN-beta/misskey"
|
||||
@@ -1195,11 +1200,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716554875,
|
||||
"narHash": "sha256-BBAiAeWPwoOJyeW9PAnxSxS9kAi2b/T8bh8ChIfAD5Q=",
|
||||
"lastModified": 1718032071,
|
||||
"narHash": "sha256-xAcK+PKIR1Z12fDMHlr2e0jzO9eIFHmRtCc8lp8MQNM=",
|
||||
"owner": "YaLTeR",
|
||||
"repo": "niri",
|
||||
"rev": "2ac8d840343dc964981507353c9128c68361cb6f",
|
||||
"rev": "22a948cc759498923c1e9806580962cdd2d7b3e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1334,11 +1339,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716692972,
|
||||
"narHash": "sha256-gz3UiLa5mdd+AoOD/p//sdTty0vWk0BLOieTM+F6dGQ=",
|
||||
"lastModified": 1717297675,
|
||||
"narHash": "sha256-43UmlS1Ifx17y93/Vc258U7bOlAAIZbu8dsGDHOIIr0=",
|
||||
"owner": "Mic92",
|
||||
"repo": "nix-index-database",
|
||||
"rev": "6e4a2b3b7c60aae5dac8c21117a134a4a56648da",
|
||||
"rev": "972a52bee3991ae1f1899e6452e0d7c01ee566d9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1355,11 +1360,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716170277,
|
||||
"narHash": "sha256-fCAiox/TuzWGVaAz16PxrR4Jtf9lN5dwWL2W74DS0yI=",
|
||||
"lastModified": 1717297675,
|
||||
"narHash": "sha256-43UmlS1Ifx17y93/Vc258U7bOlAAIZbu8dsGDHOIIr0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-index-database",
|
||||
"rev": "e0638db3db43b582512a7de8c0f8363a162842b9",
|
||||
"rev": "972a52bee3991ae1f1899e6452e0d7c01ee566d9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1393,11 +1398,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716686851,
|
||||
"narHash": "sha256-CXExi0pzojMr3A3HDgjXfRMiMuwy7ugy0FTYS8reJKc=",
|
||||
"lastModified": 1717377936,
|
||||
"narHash": "sha256-6inBsoiYEsTNJExq1G+0imL5pcDx1IkPf7PUqHARwmU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-vscode-extensions",
|
||||
"rev": "dbfae537a3320e220c3e48e611c900e2fa99e800",
|
||||
"rev": "1ae16af500525f1ca1b3295f5ee4e2b1b26f3004",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1408,11 +1413,11 @@
|
||||
},
|
||||
"nixos-hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1716434919,
|
||||
"narHash": "sha256-e4pct2Dfm8Z01CrAtUjhYy3hQ1QDJ6AG4QrZ0Qb3bI8=",
|
||||
"lastModified": 1717405269,
|
||||
"narHash": "sha256-VnVmRJNyn2BDpHitpJOo2G2nw8TtQWKMDgekKdpReuU=",
|
||||
"owner": "CHN-beta",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "d68b07afe4d8dbe11edd841dc1116fcd42ba5b01",
|
||||
"rev": "d2b7bb0a02e2f6e1fdecb8eaa8038bc0476cc621",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1423,11 +1428,11 @@
|
||||
},
|
||||
"nixos-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1716361217,
|
||||
"narHash": "sha256-mzZDr00WUiUXVm1ujBVv6A0qRd8okaITyUp4ezYRgc4=",
|
||||
"lastModified": 1717159533,
|
||||
"narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "46397778ef1f73414b03ed553a3368f0e7e33c2f",
|
||||
"rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1439,11 +1444,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1716992815,
|
||||
"narHash": "sha256-1OVNkg296i7batPGIIRSwqaf5Sq8ricVdX98aXKLtTE=",
|
||||
"lastModified": 1718293815,
|
||||
"narHash": "sha256-M8Begx/FQ5dtR+FaV1+Ff7Siq5FX2dvbFIYHNoGPdOg=",
|
||||
"owner": "CHN-beta",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7ff76d5e34d5fb398471886a181dd17a17b4e139",
|
||||
"rev": "ecd5c77a9a8b4f041b4bcb649cd219189e85987d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1531,14 +1536,14 @@
|
||||
},
|
||||
"nixpkgs-lib_2": {
|
||||
"locked": {
|
||||
"lastModified": 1714640452,
|
||||
"narHash": "sha256-QBx10+k6JWz6u7VsohfSw8g8hjdBZEf8CFzXH1/1Z94=",
|
||||
"lastModified": 1717284937,
|
||||
"narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/50eb7ecf4cd0a5756d7275c8ba36790e5bd53e33.tar.gz"
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/50eb7ecf4cd0a5756d7275c8ba36790e5bd53e33.tar.gz"
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
@@ -1635,11 +1640,11 @@
|
||||
"treefmt-nix": "treefmt-nix_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716640514,
|
||||
"narHash": "sha256-Pb2DOi9FLoM+FILY7C2x4U6lbUUkZYSWYsCU2EJAt4U=",
|
||||
"lastModified": 1717331653,
|
||||
"narHash": "sha256-6tl0PiiDrHAgihy0LLhD+yE1OAIuCdmLXmkvQp9J6sM=",
|
||||
"owner": "linyinfeng",
|
||||
"repo": "nur-packages",
|
||||
"rev": "f50a0735b4d3e30c70074d069821318f2c040c42",
|
||||
"rev": "db64978a19f5cc56db36eeabaf680c3c99796dca",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1660,11 +1665,11 @@
|
||||
"treefmt-nix": "treefmt-nix_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716618189,
|
||||
"narHash": "sha256-rHwrEDSMSJF0o/MMZ1bUmvUWUzV8mqmsSOoUO+uLEOs=",
|
||||
"lastModified": 1717396019,
|
||||
"narHash": "sha256-fXj2Ky4o5JPCOaTR/NHvcBh7jZgxC4by3UVT/9G5Tp0=",
|
||||
"owner": "xddxdd",
|
||||
"repo": "nur-packages",
|
||||
"rev": "ef294b21bc5753d2743ca5efc926d5597f303482",
|
||||
"rev": "043785e54cd3516bff03b9469535e196efbe1e06",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1831,11 +1836,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716670933,
|
||||
"narHash": "sha256-E5GqDM3cPvPNyfzt1qF7T0Wei1azp1DwLF9qA0X+5M8=",
|
||||
"lastModified": 1717344000,
|
||||
"narHash": "sha256-Gtg9wgyFUNySlzae8OpPXNnrLDpO9xshS3dGqMOYa/Y=",
|
||||
"owner": "pjones",
|
||||
"repo": "plasma-manager",
|
||||
"rev": "4d38fc602e01cc8d1e93e51677aade86febf3295",
|
||||
"rev": "7c816ab287574c317ac586900718aa7ab85f2f17",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1875,11 +1880,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716561295,
|
||||
"narHash": "sha256-U3W2Zj7hUXWFTejfFyke/owrZa4bYqUWAsRSUtqwaB0=",
|
||||
"lastModified": 1717181644,
|
||||
"narHash": "sha256-ifT/rQmhfCYkBdNnStWrsJRxxYhsEVe3LInyt29Gi3Y=",
|
||||
"owner": "Nix-QChem",
|
||||
"repo": "NixOS-QChem",
|
||||
"rev": "2279fb5d612457be80261ef5b733f344e0fc3ead",
|
||||
"rev": "a23dcbe1d26a46b95be903f22a712718a30ca300",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -1908,16 +1913,16 @@
|
||||
"rocksdb": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1714770052,
|
||||
"narHash": "sha256-NCPYF2wYBsB9OHEkZSOYoPlxjC9BBMhJp8EM5M1o3Mc=",
|
||||
"lastModified": 1716773462,
|
||||
"narHash": "sha256-5kUH+XK+2lbFfUgbxuNy3YMLHbp6scfWPdtc8za1wDM=",
|
||||
"owner": "girlbossceo",
|
||||
"repo": "rocksdb",
|
||||
"rev": "db6df0b185774778457dabfcbd822cb81760cade",
|
||||
"rev": "c8a1450231e9c608edf535538dbe8ca1a8d2f3bc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "girlbossceo",
|
||||
"ref": "v9.1.1",
|
||||
"ref": "v9.2.1",
|
||||
"repo": "rocksdb",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -1997,11 +2002,11 @@
|
||||
"rsshub": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1716667839,
|
||||
"narHash": "sha256-TQF4ZbmIyHEL4b1L0VXWur1Y8xT6Oam/qXgNJnhgzSs=",
|
||||
"lastModified": 1717336154,
|
||||
"narHash": "sha256-mzzoKQXaqisTgKpQM98F53e3ah8DmRHQ/ScYT5k+nrk=",
|
||||
"owner": "DIYgod",
|
||||
"repo": "RSSHub",
|
||||
"rev": "4cea8ac3b8a8c9668e1cc11259af715343b0fe98",
|
||||
"rev": "a0bee48d9f9d2db78e81f37194a9efc2b1a21645",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -2013,11 +2018,11 @@
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1714501997,
|
||||
"narHash": "sha256-g31zfxwUFzkPgX0Q8sZLcrqGmOxwjEZ/iqJjNx4fEGo=",
|
||||
"lastModified": 1717583671,
|
||||
"narHash": "sha256-+lRAmz92CNUxorqWusgJbL9VE1eKCnQQojglRemzwkw=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "49e502b277a8126a9ad10c802d1aaa3ef1a280ef",
|
||||
"rev": "48bbdd6a74f3176987d5c809894ac33957000d19",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -2057,11 +2062,11 @@
|
||||
"rycee": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1716696193,
|
||||
"narHash": "sha256-LDYVKXds7YlWXGez8cJZDHqiipaJQXxDbPwb8JQZA98=",
|
||||
"lastModified": 1717387398,
|
||||
"narHash": "sha256-f1UvCZdDlsmbEb/e9hn9KcxgFKS5Rf9u3IaSCh9zYkU=",
|
||||
"owner": "rycee",
|
||||
"repo": "nur-expressions",
|
||||
"rev": "4f1fb00ef0d1c486c0535b8a8cbca263467f181f",
|
||||
"rev": "be0bd738f09e66ae042365fa328efee9160677b5",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
@@ -2112,11 +2117,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716692524,
|
||||
"narHash": "sha256-sALodaA7Zkp/JD6ehgwc0UCBrSBfB4cX66uFGTsqeFU=",
|
||||
"lastModified": 1717297459,
|
||||
"narHash": "sha256-cZC2f68w5UrJ1f+2NWGV9Gx0dEYmxwomWN2B0lx0QRA=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "962797a8d7f15ed7033031731d0bb77244839960",
|
||||
"rev": "ab2a43b0d21d1d37d4d5726a892f714eaeb4b075",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -2297,11 +2302,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1715940852,
|
||||
"narHash": "sha256-wJqHMg/K6X3JGAE9YLM0LsuKrKb4XiBeVaoeMNlReZg=",
|
||||
"lastModified": 1717278143,
|
||||
"narHash": "sha256-u10aDdYrpiGOLoxzY/mJ9llST9yO8Q7K/UlROoNxzDw=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "2fba33a182602b9d49f0b2440513e5ee091d838b",
|
||||
"rev": "3eb96ca1ae9edf792a8e0963cc92fddfa5a87706",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -2318,11 +2323,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1715940852,
|
||||
"narHash": "sha256-wJqHMg/K6X3JGAE9YLM0LsuKrKb4XiBeVaoeMNlReZg=",
|
||||
"lastModified": 1717278143,
|
||||
"narHash": "sha256-u10aDdYrpiGOLoxzY/mJ9llST9yO8Q7K/UlROoNxzDw=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "2fba33a182602b9d49f0b2440513e5ee091d838b",
|
||||
"rev": "3eb96ca1ae9edf792a8e0963cc92fddfa5a87706",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -2427,14 +2432,15 @@
|
||||
"locked": {
|
||||
"lastModified": 1695926485,
|
||||
"narHash": "sha256-wNFFnItckgSs8XeYhhv8vlJs2WF09fSQaWgw4xkDqHQ=",
|
||||
"owner": "UbiqueLambda",
|
||||
"repo": "yafas",
|
||||
"rev": "7772afd6686458ca0ddbc599a52cf5d337367653",
|
||||
"revCount": 4,
|
||||
"type": "tarball",
|
||||
"url": "https://api.flakehub.com/f/pinned/UbiqueLambda/yafas/0.1.4%2Brev-7772afd6686458ca0ddbc599a52cf5d337367653/018add18-ebb4-72c6-93fe-d1d8da361703/source.tar.gz"
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://flakehub.com/f/UbiqueLambda/yafas/0.1.%2A.tar.gz"
|
||||
"owner": "UbiqueLambda",
|
||||
"repo": "yafas",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zpp-bits": {
|
||||
|
||||
42
flake.nix
42
flake.nix
@@ -94,10 +94,15 @@
|
||||
(system: builtins.toString inputs.self.outputs.nixosConfigurations.${system}.config.system.build.toplevel)
|
||||
devices));
|
||||
hpcstat =
|
||||
let openssh = (pkgs.pkgsStatic.openssh.override { withLdns = false; etcDir = null; }).overrideAttrs
|
||||
(prev: { doCheck = false; patches = prev.patches ++ [ ./local/pkgs/hpcstat/openssh.patch ];});
|
||||
let
|
||||
openssh = (pkgs.pkgsStatic.openssh.override { withLdns = false; etcDir = null; }).overrideAttrs
|
||||
(prev: { doCheck = false; patches = prev.patches ++ [ ./local/pkgs/hpcstat/openssh.patch ];});
|
||||
duc = pkgs.pkgsStatic.duc.override { enableCairo = false; cairo = null; pango = null; };
|
||||
in pkgs.pkgsStatic.localPackages.hpcstat.override
|
||||
{ inherit openssh; standalone = true; version = inputs.self.rev or "dirty"; };
|
||||
{ inherit openssh duc; standalone = true; version = inputs.self.rev or "dirty"; };
|
||||
ufo = pkgs.pkgsStatic.localPackages.ufo.override { version = inputs.self.rev or "dirty"; };
|
||||
chn-bsub = pkgs.pkgsStatic.localPackages.chn-bsub;
|
||||
nixpkgs = pkgs;
|
||||
}
|
||||
// (
|
||||
builtins.listToAttrs (builtins.map
|
||||
@@ -169,7 +174,7 @@
|
||||
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks inputs.self.deploy) inputs.deploy-rs.lib;
|
||||
overlays.default = final: prev:
|
||||
{ localPackages = (import ./local/pkgs { inherit (inputs) lib; pkgs = final; topInputs = inputs; }); };
|
||||
config.archive = false;
|
||||
config = { archive = false; branch = "production"; };
|
||||
devShells.x86_64-linux =
|
||||
let pkgs = (import inputs.nixpkgs
|
||||
{
|
||||
@@ -181,17 +186,32 @@
|
||||
{
|
||||
biu = pkgs.mkShell
|
||||
{
|
||||
packages = with pkgs; [ pkg-config cmake ninja clang-tools_17 ];
|
||||
buildInputs =
|
||||
(with pkgs; [ fmt boost magic-enum libbacktrace eigen range-v3 ])
|
||||
++ (with pkgs.localPackages; [ concurrencpp tgbot-cpp nameof ]);
|
||||
# hardeningDisable = [ "all" ];
|
||||
# NIX_DEBUG = "1";
|
||||
inputsFrom = with pkgs.localPackages; [ biu ];
|
||||
buildInputs = [ pkgs.clang-tools_18 ];
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
|
||||
};
|
||||
hpcstat = pkgs.mkShell
|
||||
{
|
||||
inputsFrom = [ (inputs.self.packages.x86_64-linux.hpcstat.override { version = null; }) ];
|
||||
packages = [ pkgs.clang-tools_17 ];
|
||||
packages = [ pkgs.clang-tools_18 ];
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
|
||||
};
|
||||
sbatch-tui = pkgs.mkShell
|
||||
{
|
||||
inputsFrom = with pkgs.localPackages; [ sbatch-tui ];
|
||||
buildInputs = [ pkgs.clang-tools_18 ];
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
|
||||
};
|
||||
ufo = pkgs.mkShell
|
||||
{
|
||||
inputsFrom = [ (inputs.self.packages.x86_64-linux.ufo.override { version = null; }) ];
|
||||
packages = [ pkgs.clang-tools_18 ];
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
|
||||
};
|
||||
chn-bsub = pkgs.mkShell
|
||||
{
|
||||
inputsFrom = with pkgs.localPackages; [ chn-bsub ];
|
||||
buildInputs = [ pkgs.clang-tools_18 ];
|
||||
CMAKE_EXPORT_COMPILE_COMMANDS = "1";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
CompileFlags:
|
||||
Add: [ -Wall, -Wextra, -std=c++23 ]
|
||||
Compiler: gcc
|
||||
Compiler: g++
|
||||
@@ -3,6 +3,8 @@ project(biu LANGUAGES CXX)
|
||||
enable_testing()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message("Setting build type to 'Release' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
@@ -12,33 +14,23 @@ endif()
|
||||
find_package(magic_enum REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS headers iostreams)
|
||||
# find_package(concurrencpp REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_path(NAMEOF_INCLUDE_DIR nameof.hpp REQUIRED)
|
||||
# find_path(TGBOTCPP_INCLUDE_DIR tgbot/tgbot.h REQUIRED)
|
||||
# find_library(TGBOTCPP_LIB libTgBot.a REQUIRED)
|
||||
# find_path(BACKTRACE_INCLUDE_DIR backtrace.h REQUIRED)
|
||||
# find_library(BACKTRACE_LIB backtrace REQUIRED)
|
||||
find_path(ZPP_BITS_INCLUDE_DIR zpp_bits.h REQUIRED)
|
||||
|
||||
# add_library(biu SHARED src/common.cpp src/logger.cpp src/string.cpp)
|
||||
add_library(biu SHARED src/common.cpp)
|
||||
target_include_directories(biu PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
${NAMEOF_INCLUDE_DIR} ${TGBOTCPP_INCLUDE_DIR})
|
||||
target_link_libraries(biu PUBLIC
|
||||
magic_enum::magic_enum
|
||||
fmt::fmt
|
||||
Boost::headers Boost::iostreams
|
||||
# concurrencpp::concurrencpp
|
||||
Eigen3::Eigen
|
||||
add_library(biu src/common.cpp)
|
||||
target_include_directories(biu PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> ${NAMEOF_INCLUDE_DIR} ${ZPP_BITS_INCLUDE_DIR})
|
||||
target_link_libraries(biu PUBLIC magic_enum::magic_enum fmt::fmt Boost::headers Boost::iostreams Eigen3::Eigen
|
||||
range-v3::range-v3)
|
||||
# ${TGBOTCPP_LIB} ${BACKTRACE_LIB})
|
||||
set_property(TARGET biu PROPERTY CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF)
|
||||
install(TARGETS biu EXPORT biuConfig)
|
||||
install(EXPORT biuConfig NAMESPACE ${PROJECT_NAME}:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/biu)
|
||||
install(TARGETS biu EXPORT biuTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(EXPORT biuTargets FILE biuTargets.cmake NAMESPACE biu:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/biu)
|
||||
install(FILES biuConfig.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/biu)
|
||||
|
||||
get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS)
|
||||
message("Imported targets: ${ImportedTargets}")
|
||||
|
||||
49
local/pkgs/biu/README.md
Normal file
49
local/pkgs/biu/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# `common`:
|
||||
|
||||
```c++
|
||||
// get hash of any object
|
||||
std::size_t hash(auto&&... objs);
|
||||
// suppress unused variable warning
|
||||
void unused(auto&&...);
|
||||
// block forever
|
||||
void block_forever();
|
||||
detail_::ExecResult exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin,
|
||||
std::map<std::string, std::string> extra_env
|
||||
);
|
||||
|
||||
using int128_t = ...;
|
||||
using uint128_t = ...;
|
||||
|
||||
struct CaseInsensitiveStringLessComparator {...};
|
||||
|
||||
// remove Class::*
|
||||
template <typename MemberPointer> using RemoveMemberPointer = ...;
|
||||
// move qualifiers (cvref) from From to To
|
||||
template <typename From, typename To> using MoveQualifiers = ...;
|
||||
// get T::type or T::Type if exists, otherwise Fallback
|
||||
template <typename T, typename Fallback = void> using FallbackIfNoTypeDeclared
|
||||
```
|
||||
|
||||
# `inline literals`
|
||||
|
||||
```c++
|
||||
using namespace std::literals;
|
||||
using namespace fmt::literals;
|
||||
std::regex operator""_re(const char* str, std::size_t len);
|
||||
```
|
||||
|
||||
# `inline stream_operators`:
|
||||
|
||||
```c++
|
||||
inline namespace stream_operators { using namespace magic_enum::iostream_operators; }
|
||||
```
|
||||
|
||||
# `env`
|
||||
|
||||
```c++
|
||||
bool is_interactive();
|
||||
std::optional<std::string> env(std::string name);
|
||||
std::map<std::string, std::string> env();
|
||||
```
|
||||
7
local/pkgs/biu/biuConfig.cmake
Normal file
7
local/pkgs/biu/biuConfig.cmake
Normal file
@@ -0,0 +1,7 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/biuTargets.cmake")
|
||||
find_package(magic_enum REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS headers iostreams)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_path(NAMEOF_INCLUDE_DIR nameof.hpp REQUIRED)
|
||||
@@ -1,10 +1,11 @@
|
||||
{
|
||||
stdenv, cmake,
|
||||
magic-enum, fmt, boost, eigen, range-v3, nameof
|
||||
}: stdenv.mkDerivation
|
||||
magic-enum, fmt, boost, eigen, range-v3, nameof, zpp-bits
|
||||
}: stdenv.mkDerivation rec
|
||||
{
|
||||
name = "biu";
|
||||
src = ./.;
|
||||
buildInputs = [ magic-enum fmt boost eigen range-v3 nameof ];
|
||||
buildInputs = [ magic-enum fmt boost eigen range-v3 nameof zpp-bits ];
|
||||
propagatedBuildInputs = buildInputs;
|
||||
nativeBuildInputs = [ cmake ];
|
||||
}
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
// # include <biu/atomic/atomic.tpp>
|
||||
// # include <biu/called_by.hpp>
|
||||
# include <biu/common.tpp>
|
||||
// # include <biu/concepts.tpp>
|
||||
// # include <biu/format.tpp>
|
||||
# include <biu/concepts.tpp>
|
||||
# include <biu/string.tpp>
|
||||
# include <biu/format.tpp>
|
||||
// # include <biu/logger.tpp>
|
||||
// # include <biu/smartref.tpp>
|
||||
// # include <biu/string.tpp>
|
||||
# include <biu/eigen.hpp>
|
||||
|
||||
// # include <biu/eigen.hpp>
|
||||
|
||||
@@ -1,66 +1,108 @@
|
||||
# pragma once
|
||||
# include <regex>
|
||||
# include <optional>
|
||||
# include <filesystem>
|
||||
# include <fmt/format.h>
|
||||
# include <magic_enum.hpp>
|
||||
# include <magic_enum_all.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
std::size_t hash(auto&&... objs);
|
||||
[[gnu::always_inline]] void unused(auto&&...);
|
||||
inline namespace literals
|
||||
{
|
||||
using namespace std::literals;
|
||||
using namespace fmt::literals;
|
||||
std::regex operator""_re(const char* str, std::size_t len);
|
||||
}
|
||||
inline namespace stream_operators { using namespace magic_enum::iostream_operators; }
|
||||
namespace common
|
||||
{
|
||||
std::size_t hash(auto&&... objs);
|
||||
[[gnu::always_inline]] void unused(auto&&...);
|
||||
[[noreturn]] void block_forever();
|
||||
|
||||
using uint128_t = __uint128_t;
|
||||
bool is_interactive();
|
||||
std::optional<std::string> env(std::string name);
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
using namespace std::literals;
|
||||
using namespace fmt::literals;
|
||||
std::regex operator""_re(const char* str, std::size_t len);
|
||||
}
|
||||
using int128_t = __int128_t;
|
||||
using uint128_t = __uint128_t;
|
||||
|
||||
inline namespace stream_operators { using namespace magic_enum::iostream_operators; }
|
||||
struct Empty {};
|
||||
|
||||
struct CaseInsensitiveStringLessComparator
|
||||
{
|
||||
template <typename String> constexpr bool operator()(const String& s1, const String& s2) const;
|
||||
};
|
||||
struct CaseInsensitiveStringLessComparator
|
||||
{
|
||||
template <typename String> constexpr bool operator()(const String& s1, const String& s2) const;
|
||||
};
|
||||
namespace detail_
|
||||
{
|
||||
template <typename T> struct RemoveMemberPointerHelper { using Type = T; };
|
||||
template <typename Class, typename Member> struct RemoveMemberPointerHelper<Member Class::*>
|
||||
{ using Type = Member; };
|
||||
}
|
||||
template <typename MemberPointer> using RemoveMemberPointer
|
||||
= typename detail_::RemoveMemberPointerHelper<MemberPointer>::Type;
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename T> struct RemoveMemberPointerHelper { using Type = T; };
|
||||
template <typename Class, typename Member> struct RemoveMemberPointerHelper<Member Class::*>
|
||||
{ using Type = Member; };
|
||||
}
|
||||
template <typename MemberPointer> using RemoveMemberPointer
|
||||
= typename detail_::RemoveMemberPointerHelper<MemberPointer>::Type;
|
||||
namespace detail_
|
||||
{
|
||||
template <typename From, typename To> struct MoveQualifiersHelper
|
||||
{
|
||||
protected: static constexpr bool Const_ = std::is_const_v<From>;
|
||||
protected: static constexpr bool Volatile_ = std::is_volatile_v<From>;
|
||||
protected: static constexpr bool Reference_ = std::is_reference_v<From>;
|
||||
protected: static constexpr bool Lvalue_ = std::is_lvalue_reference_v<From>;
|
||||
protected: using NoCvrefType_ = std::remove_cvref_t<To>;
|
||||
protected: using NoCvType_
|
||||
= std::conditional_t<Reference_, std::conditional_t<Lvalue_, NoCvrefType_&, NoCvrefType_&&>, NoCvrefType_>;
|
||||
protected: using NoConstType_ = std::conditional_t<Volatile_, volatile NoCvType_, NoCvType_>;
|
||||
public: using Type = std::conditional_t<Const_, const NoConstType_, NoConstType_>;
|
||||
};
|
||||
}
|
||||
template <typename From, typename To> using MoveQualifiers
|
||||
= typename detail_::MoveQualifiersHelper<From, To>::Type;
|
||||
|
||||
[[noreturn]] void block_forever();
|
||||
namespace detail_
|
||||
{
|
||||
template <typename T, typename Fallback = void> struct FallbackIfNoTypeDeclaredHelper { using Type = Fallback; };
|
||||
template <typename T, typename Fallback> requires requires { typename T::Type; }
|
||||
struct FallbackIfNoTypeDeclaredHelper<T, Fallback> { using Type = typename T::Type; };
|
||||
template <typename T, typename Fallback> requires requires {typename T::type;}
|
||||
struct FallbackIfNoTypeDeclaredHelper<T, Fallback> { using Type = typename T::type; };
|
||||
}
|
||||
template <typename T, typename Fallback = void> using FallbackIfNoTypeDeclared
|
||||
= typename detail_::FallbackIfNoTypeDeclaredHelper<T, Fallback>::Type;
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename From, typename To> struct MoveQualifiersHelper
|
||||
{
|
||||
protected: static constexpr bool Const_ = std::is_const_v<From>;
|
||||
protected: static constexpr bool Volatile_ = std::is_volatile_v<From>;
|
||||
protected: static constexpr bool Reference_ = std::is_reference_v<From>;
|
||||
protected: static constexpr bool Lvalue_ = std::is_lvalue_reference_v<From>;
|
||||
protected: using NoCvrefType_ = std::remove_cvref_t<To>;
|
||||
protected: using NoCvType_
|
||||
= std::conditional_t<Reference_, std::conditional_t<Lvalue_, NoCvrefType_&, NoCvrefType_&&>, NoCvrefType_>;
|
||||
protected: using NoConstType_ = std::conditional_t<Volatile_, volatile NoCvType_, NoCvType_>;
|
||||
public: using Type = std::conditional_t<Const_, const NoConstType_, NoConstType_>;
|
||||
};
|
||||
}
|
||||
template <typename From, typename To> using MoveQualifiers
|
||||
= typename detail_::MoveQualifiersHelper<From, To>::Type;
|
||||
namespace detail_
|
||||
{
|
||||
template <bool DirectStdout, bool DirectStderr> struct ExecResult
|
||||
{
|
||||
int ExitCode;
|
||||
std::conditional_t<DirectStdout, Empty, std::string> Stdout;
|
||||
std::conditional_t<DirectStderr, Empty, std::string> Stderr;
|
||||
operator bool() const;
|
||||
};
|
||||
struct ExecInput { bool DirectStdin = false, DirectStdout = false, DirectStderr = false, SearchPath = false; };
|
||||
}
|
||||
template <detail_::ExecInput Input = {}> requires (!Input.DirectStdin)
|
||||
detail_::ExecResult<Input.DirectStdout, Input.DirectStderr> exec
|
||||
(
|
||||
std::conditional_t<Input.SearchPath, std::string, std::filesystem::path> program, std::vector<std::string> args,
|
||||
std::optional<std::string> stdin_string = {}, std::map<std::string, std::string> extra_env = {}
|
||||
);
|
||||
template <detail_::ExecInput Input = {}> requires (Input.DirectStdin)
|
||||
detail_::ExecResult<Input.DirectStdout, Input.DirectStderr> exec
|
||||
(
|
||||
std::conditional_t<Input.SearchPath, std::string, std::filesystem::path> program, std::vector<std::string> args,
|
||||
std::map<std::string, std::string> extra_env = {}
|
||||
);
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename T, typename Fallback = void> struct FallbackIfNoTypeDeclaredHelper { using Type = Fallback; };
|
||||
template <typename T, typename Fallback> requires requires { typename T::Type; }
|
||||
struct FallbackIfNoTypeDeclaredHelper<T, Fallback> { using Type = typename T::Type; };
|
||||
template <typename T, typename Fallback> requires requires {typename T::type;}
|
||||
struct FallbackIfNoTypeDeclaredHelper<T, Fallback> { using Type = typename T::type; };
|
||||
}
|
||||
template <typename T, typename Fallback = void> using FallbackIfNoTypeDeclared
|
||||
= typename detail_::FallbackIfNoTypeDeclaredHelper<T, Fallback>::Type;
|
||||
static_assert(sizeof(char) == sizeof(std::byte));
|
||||
template <typename Char = std::byte, typename T> requires (std::same_as<Char, std::byte>)
|
||||
std::vector<std::byte> serialize(const T& data);
|
||||
template <typename Char = std::byte, typename T> requires (std::same_as<Char, char>)
|
||||
std::string serialize(const T& data);
|
||||
template <typename T> T deserialize(const std::string& serialized_data);
|
||||
template <typename T> T deserialize(const std::vector<std::byte>& serialized_data);
|
||||
}
|
||||
using common::hash, common::unused, common::block_forever, common::is_interactive, common::env, common::int128_t,
|
||||
common::uint128_t, common::Empty, common::CaseInsensitiveStringLessComparator, common::RemoveMemberPointer,
|
||||
common::MoveQualifiers, common::FallbackIfNoTypeDeclared, common::exec, common::serialize, common::deserialize;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,50 @@
|
||||
# pragma once
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <zpp_bits.h>
|
||||
# include <biu/common.hpp>
|
||||
|
||||
namespace biu
|
||||
namespace biu::common
|
||||
{
|
||||
inline void unused(auto&&...) {}
|
||||
inline std::size_t hash(auto&&... objs)
|
||||
{
|
||||
std::size_t result = 0;
|
||||
(boost::hash_combine(result, objs), ...);
|
||||
return result;
|
||||
}
|
||||
void unused(auto&&...) {}
|
||||
std::size_t hash(auto&&... objs)
|
||||
{
|
||||
std::size_t result = 0;
|
||||
(boost::hash_combine(result, objs), ...);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename String> inline constexpr bool CaseInsensitiveStringLessComparator::operator()
|
||||
(const String& s1, const String& s2) const
|
||||
{
|
||||
return std::lexicographical_compare
|
||||
(
|
||||
s1.begin(), s1.end(), s2.begin(), s2.end(),
|
||||
[](char c1, char c2){return std::tolower(c1) < std::tolower(c2);}
|
||||
);
|
||||
}
|
||||
}
|
||||
template <typename String> constexpr bool CaseInsensitiveStringLessComparator::operator()
|
||||
(const String& s1, const String& s2) const
|
||||
{
|
||||
return std::lexicographical_compare
|
||||
(
|
||||
s1.begin(), s1.end(), s2.begin(), s2.end(),
|
||||
[](char c1, char c2){return std::tolower(c1) < std::tolower(c2);}
|
||||
);
|
||||
}
|
||||
|
||||
template <typename Char, typename T> requires (std::same_as<Char, std::byte>)
|
||||
std::vector<std::byte> serialize(const T& data)
|
||||
{
|
||||
auto [serialized_data, out] = zpp::bits::data_out();
|
||||
out(data).or_throw();
|
||||
return serialized_data;
|
||||
}
|
||||
template <typename Char, typename T> requires (std::same_as<Char, char>) std::string serialize(const T& data)
|
||||
{
|
||||
auto serialized_data = serialize<std::byte>(data);
|
||||
return {reinterpret_cast<const char*>(serialized_data.data()), serialized_data.size()};
|
||||
}
|
||||
template <typename T> T deserialize(const std::vector<std::byte>& serialized_data)
|
||||
{
|
||||
auto in = zpp::bits::in(serialized_data);
|
||||
T data;
|
||||
in(data).or_throw();
|
||||
return data;
|
||||
}
|
||||
template <typename T> T deserialize(const std::string& serialized_data)
|
||||
{
|
||||
auto begin = reinterpret_cast<const std::byte*>(serialized_data.data()), end = begin + serialized_data.size();
|
||||
return deserialize<T>(std::vector<std::byte>{begin, end});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,42 +6,49 @@
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <typename T> concept DecayedType = std::same_as<std::decay_t<T>, T>;
|
||||
namespace concepts
|
||||
{
|
||||
template <typename T> concept DecayedType = std::same_as<std::decay_t<T>, T>;
|
||||
|
||||
namespace detail_::specialization_of_detail_
|
||||
{
|
||||
template <typename Tuple> struct DropFirstMemberOfTupleHelper;
|
||||
template <typename First, typename... Others> struct DropFirstMemberOfTupleHelper<std::tuple<First, Others...>>
|
||||
{using Type = std::tuple<Others...>;};
|
||||
template <typename ProvidedArgs, typename ActualArgs> consteval bool check_provided_args();
|
||||
template <typename Class, template <typename...> typename Template> struct SpecializationOfHelper
|
||||
{template <typename... ProvidedArgs> consteval static bool check_provided_args();};
|
||||
template <template <typename...> typename Template, typename... ActualArgs>
|
||||
struct SpecializationOfHelper<Template<ActualArgs...>, Template>
|
||||
{template <typename... ProvidedArgs> consteval static bool check_provided_args();};
|
||||
}
|
||||
template <typename Class, template <typename...> typename Template, typename... ProvidedArgs>
|
||||
concept SpecializationOf
|
||||
= detail_::specialization_of_detail_::SpecializationOfHelper<std::decay_t<Class>, Template>
|
||||
::template check_provided_args<ProvidedArgs...>();
|
||||
namespace detail_::specialization_of_detail_
|
||||
{
|
||||
template <typename Tuple> struct DropFirstMemberOfTupleHelper;
|
||||
template <typename First, typename... Others> struct DropFirstMemberOfTupleHelper<std::tuple<First, Others...>>
|
||||
{using Type = std::tuple<Others...>;};
|
||||
template <typename ProvidedArgs, typename ActualArgs> consteval bool check_provided_args();
|
||||
template <typename Class, template <typename...> typename Template> struct SpecializationOfHelper
|
||||
{template <typename... ProvidedArgs> consteval static bool check_provided_args();};
|
||||
template <template <typename...> typename Template, typename... ActualArgs>
|
||||
struct SpecializationOfHelper<Template<ActualArgs...>, Template>
|
||||
{template <typename... ProvidedArgs> consteval static bool check_provided_args();};
|
||||
}
|
||||
template <typename Class, template <typename...> typename Template, typename... ProvidedArgs>
|
||||
concept SpecializationOf
|
||||
= detail_::specialization_of_detail_::SpecializationOfHelper<std::decay_t<Class>, Template>
|
||||
::template check_provided_args<ProvidedArgs...>();
|
||||
|
||||
template <typename T> concept CompletedType = sizeof(T) == sizeof(T);
|
||||
template <typename T> concept CompletedType = sizeof(T) == sizeof(T);
|
||||
|
||||
template <typename From, typename To> concept ImplicitlyConvertibleTo = std::is_convertible<From, To>::value;
|
||||
template <typename To, typename From> concept ImplicitlyConvertibleFrom = std::is_convertible<From, To>::value;
|
||||
template <typename From, typename To> concept ExplicitlyConvertibleTo = std::is_constructible<To, From>::value;
|
||||
template <typename To, typename From> concept ExplicitlyConvertibleFrom = std::is_constructible<To, From>::value;
|
||||
template <typename From, typename To> concept ConvertibleTo
|
||||
= ImplicitlyConvertibleTo<From, To> || ExplicitlyConvertibleTo<From, To>;
|
||||
template <typename From, typename To> concept ConvertibleFrom = ConvertibleTo<From, To>;
|
||||
template <typename From, typename To> concept ImplicitlyConvertibleTo = std::is_convertible<From, To>::value;
|
||||
template <typename To, typename From> concept ImplicitlyConvertibleFrom = std::is_convertible<From, To>::value;
|
||||
template <typename From, typename To> concept ExplicitlyConvertibleTo = std::is_constructible<To, From>::value;
|
||||
template <typename To, typename From> concept ExplicitlyConvertibleFrom = std::is_constructible<To, From>::value;
|
||||
template <typename From, typename To> concept ConvertibleTo
|
||||
= ImplicitlyConvertibleTo<From, To> || ExplicitlyConvertibleTo<From, To>;
|
||||
template <typename From, typename To> concept ConvertibleFrom = ConvertibleTo<From, To>;
|
||||
|
||||
template <typename Function, auto... Args> concept ConstevalInvokable
|
||||
= requires() {typename std::type_identity_t<int[(Function()(Args...), 1)]>;};
|
||||
template <typename Function, auto... Args> concept ConstevalInvokable
|
||||
= requires() {typename std::type_identity_t<int[(Function()(Args...), 1)]>;};
|
||||
|
||||
template <typename T> concept Enumerable = std::is_enum_v<T>;
|
||||
template <typename T> concept Enumerable = std::is_enum_v<T>;
|
||||
|
||||
template <typename Function, typename Result, typename... Args> concept InvocableWithResult
|
||||
= std::is_invocable_r_v<Result, Function, Args...>;
|
||||
|
||||
template <typename T> concept Arithmetic = std::is_arithmetic<T>::value || SpecializationOf<T, std::complex>;
|
||||
template <typename Function, typename Result, typename... Args> concept InvocableWithResult
|
||||
= std::is_invocable_r_v<Result, Function, Args...>;
|
||||
|
||||
template <typename T> concept Arithmetic = std::is_arithmetic<T>::value || SpecializationOf<T, std::complex>;
|
||||
}
|
||||
using concepts::DecayedType, concepts::SpecializationOf, concepts::CompletedType, concepts::ImplicitlyConvertibleTo,
|
||||
concepts::ImplicitlyConvertibleFrom, concepts::ExplicitlyConvertibleTo, concepts::ExplicitlyConvertibleFrom,
|
||||
concepts::ConvertibleTo, concepts::ConvertibleFrom, concepts::ConstevalInvokable, concepts::Enumerable,
|
||||
concepts::InvocableWithResult, concepts::Arithmetic;
|
||||
}
|
||||
|
||||
@@ -2,33 +2,33 @@
|
||||
# include <tuple>
|
||||
# include <biu/concepts.hpp>
|
||||
|
||||
namespace biu
|
||||
namespace biu::concepts
|
||||
{
|
||||
template <typename ProvidedArgs, typename ActualArgs> consteval bool
|
||||
detail_::specialization_of_detail_::check_provided_args()
|
||||
{
|
||||
if constexpr (std::tuple_size_v<ProvidedArgs> == 0)
|
||||
return true;
|
||||
else if constexpr (std::tuple_size_v<ActualArgs> == 0)
|
||||
return false;
|
||||
else if constexpr
|
||||
(std::same_as<std::tuple_element_t<0, ProvidedArgs>, std::tuple_element_t<0, ActualArgs>>)
|
||||
return check_provided_args
|
||||
<
|
||||
typename DropFirstMemberOfTupleHelper<ProvidedArgs>::Type,
|
||||
typename DropFirstMemberOfTupleHelper<ActualArgs>::Type
|
||||
>();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
template <typename Class, template <typename...> typename Template> template <typename... ProvidedArgs> consteval
|
||||
bool detail_::specialization_of_detail_::SpecializationOfHelper<Class, Template>::check_provided_args()
|
||||
{ return false; }
|
||||
template <template <typename...> typename Template, typename... ActualArgs> template <typename... ProvidedArgs>
|
||||
consteval bool detail_::specialization_of_detail_::SpecializationOfHelper
|
||||
<Template<ActualArgs...>, Template>::check_provided_args()
|
||||
{
|
||||
return specialization_of_detail_::check_provided_args
|
||||
<std::tuple<ProvidedArgs...>, std::tuple<ActualArgs...>>();
|
||||
}
|
||||
template <typename ProvidedArgs, typename ActualArgs> consteval bool
|
||||
detail_::specialization_of_detail_::check_provided_args()
|
||||
{
|
||||
if constexpr (std::tuple_size_v<ProvidedArgs> == 0)
|
||||
return true;
|
||||
else if constexpr (std::tuple_size_v<ActualArgs> == 0)
|
||||
return false;
|
||||
else if constexpr
|
||||
(std::same_as<std::tuple_element_t<0, ProvidedArgs>, std::tuple_element_t<0, ActualArgs>>)
|
||||
return check_provided_args
|
||||
<
|
||||
typename DropFirstMemberOfTupleHelper<ProvidedArgs>::Type,
|
||||
typename DropFirstMemberOfTupleHelper<ActualArgs>::Type
|
||||
>();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
template <typename Class, template <typename...> typename Template> template <typename... ProvidedArgs> consteval
|
||||
bool detail_::specialization_of_detail_::SpecializationOfHelper<Class, Template>::check_provided_args()
|
||||
{ return false; }
|
||||
template <template <typename...> typename Template, typename... ActualArgs> template <typename... ProvidedArgs>
|
||||
consteval bool detail_::specialization_of_detail_::SpecializationOfHelper
|
||||
<Template<ActualArgs...>, Template>::check_provided_args()
|
||||
{
|
||||
return specialization_of_detail_::check_provided_args
|
||||
<std::tuple<ProvidedArgs...>, std::tuple<ActualArgs...>>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,66 +7,65 @@
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <typename T, typename Char = char> concept Formattable = fmt::is_formattable<T, Char>::value;
|
||||
namespace concepts
|
||||
{ template <typename T, typename Char = char> concept Formattable = fmt::is_formattable<T, Char>::value; }
|
||||
using concepts::Formattable;
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename Char, Char... c> struct FormatLiteralHelper : protected BasicStaticString<Char, c...>
|
||||
{template <typename... Param> std::basic_string<Char> operator()(Param&&... param) const;};
|
||||
}
|
||||
namespace literals
|
||||
{template <typename Char, Char... c> consteval detail_::FormatLiteralHelper<Char, c...> operator""_f();}
|
||||
namespace detail_
|
||||
{
|
||||
template <typename Char, Char... c> struct FormatLiteralHelper : protected BasicStaticString<Char, c...>
|
||||
{template <typename... Param> std::basic_string<Char> operator()(Param&&... param) const;};
|
||||
}
|
||||
inline namespace literals
|
||||
{ template <typename Char, Char... c> consteval detail_::FormatLiteralHelper<Char, c...> operator""_f(); }
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename T> concept OptionalWrap
|
||||
= SpecializationOf<T, std::optional> || SpecializationOf<T, std::shared_ptr>
|
||||
|| SpecializationOf<T, std::weak_ptr> || SpecializationOf<T, std::unique_ptr>
|
||||
|| SpecializationOf<T, std::experimental::observer_ptr>;
|
||||
template <typename Wrap> struct UnderlyingTypeOfOptionalWrap;
|
||||
template <typename Wrap> requires requires() {typename Wrap::value_type;}
|
||||
struct UnderlyingTypeOfOptionalWrap<Wrap>
|
||||
{using Type = std::remove_cvref_t<typename Wrap::value_type>;};
|
||||
template <typename Wrap> requires requires() {typename Wrap::element_type;}
|
||||
struct UnderlyingTypeOfOptionalWrap<Wrap>
|
||||
{using Type = std::remove_cvref_t<typename Wrap::element_type>;};
|
||||
template <typename T> struct FormatterReuseProxy
|
||||
{
|
||||
constexpr auto parse(fmt::format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&fmt::format_parse_context::begin), fmt::format_parse_context>;
|
||||
};
|
||||
template <typename T>
|
||||
requires (!SpecializationOf<T, std::weak_ptr> && std::default_initializable<fmt::formatter<T>>)
|
||||
struct FormatterReuseProxy<T> : fmt::formatter<T> {};
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <typename Char, typename... Ts> requires (sizeof...(Ts) > 0) basic_ostream<Char>& operator<<
|
||||
(basic_ostream<Char>& os, const variant<Ts...>& value);
|
||||
namespace detail_
|
||||
{
|
||||
template <typename T> concept OptionalWrap
|
||||
= SpecializationOf<T, std::optional> || SpecializationOf<T, std::shared_ptr>
|
||||
|| SpecializationOf<T, std::weak_ptr> || SpecializationOf<T, std::unique_ptr>
|
||||
|| SpecializationOf<T, std::experimental::observer_ptr>;
|
||||
template <typename Wrap> struct UnderlyingTypeOfOptionalWrap;
|
||||
template <typename Wrap> requires requires() {typename Wrap::value_type;}
|
||||
struct UnderlyingTypeOfOptionalWrap<Wrap>
|
||||
{using Type = std::remove_cvref_t<typename Wrap::value_type>;};
|
||||
template <typename Wrap> requires requires() {typename Wrap::element_type;}
|
||||
struct UnderlyingTypeOfOptionalWrap<Wrap>
|
||||
{using Type = std::remove_cvref_t<typename Wrap::element_type>;};
|
||||
template <typename T> struct FormatterReuseProxy
|
||||
{
|
||||
constexpr auto parse(fmt::format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&fmt::format_parse_context::begin), fmt::format_parse_context>;
|
||||
};
|
||||
template <typename T>
|
||||
requires (!SpecializationOf<T, std::weak_ptr> && std::default_initializable<fmt::formatter<T>>)
|
||||
struct FormatterReuseProxy<T> : fmt::formatter<T> {};
|
||||
}
|
||||
inline namespace stream_operators
|
||||
{
|
||||
template <typename Char, typename... Ts> requires (sizeof...(Ts) > 0) std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, const std::variant<Ts...>& value);
|
||||
}
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
using namespace biu::stream_operators;
|
||||
template <typename Char, biu::detail_::OptionalWrap Wrap> struct formatter<Wrap, Char>
|
||||
: biu::detail_::FormatterReuseProxy<typename biu::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type>
|
||||
{
|
||||
template <typename FormatContext> auto format(const Wrap& wrap, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>;
|
||||
};
|
||||
|
||||
template <typename Char, biu::detail_::OptionalWrap Wrap> struct formatter<Wrap, Char>
|
||||
: biu::detail_::FormatterReuseProxy<typename biu::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type>
|
||||
{
|
||||
template <typename FormatContext> auto format(const Wrap& wrap, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>;
|
||||
};
|
||||
template <typename Char, biu::Enumerable T> struct formatter<T, Char>
|
||||
{
|
||||
bool full = false;
|
||||
constexpr auto parse(fmt::format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&fmt::format_parse_context::begin), fmt::format_parse_context>;
|
||||
template <typename FormatContext> auto format(const T& value, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>;
|
||||
};
|
||||
|
||||
template <typename Char, biu::Enumerable T> struct formatter<T, Char>
|
||||
{
|
||||
bool full = false;
|
||||
constexpr auto parse(fmt::format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&fmt::format_parse_context::begin), fmt::format_parse_context>;
|
||||
template <typename FormatContext> auto format(const T& value, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>;
|
||||
};
|
||||
|
||||
template <typename Char, typename... Ts> struct formatter<std::variant<Ts...>, Char>
|
||||
: basic_ostream_formatter<Char> {};
|
||||
template <typename Char, typename... Ts> struct formatter<std::variant<Ts...>, Char>
|
||||
: basic_ostream_formatter<Char> {};
|
||||
}
|
||||
|
||||
@@ -1,122 +1,92 @@
|
||||
# pragma once
|
||||
# include <nameof.hpp>
|
||||
# include <biu/format.hpp>
|
||||
# include <fmt/core.h>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <typename Char, Char... c> template <typename... Param>
|
||||
std::basic_string<Char> detail_::FormatLiteralHelper<Char, c...>::operator() (Param&&... param) const
|
||||
{return fmt::format(BasicStaticString<Char, c...>::StringView, std::forward<Param>(param)...);}
|
||||
template <typename Char, Char... c> consteval
|
||||
detail_::FormatLiteralHelper<Char, c...> literals::operator""_f()
|
||||
{return {};}
|
||||
template <typename Char, Char... c> template <typename... Param>
|
||||
std::basic_string<Char> detail_::FormatLiteralHelper<Char, c...>::operator() (Param&&... param) const
|
||||
{ return fmt::format(BasicStaticString<Char, c...>::StringView, std::forward<Param>(param)...); }
|
||||
template <typename Char, Char... c> consteval
|
||||
detail_::FormatLiteralHelper<Char, c...> literals::operator""_f()
|
||||
{ return {}; }
|
||||
|
||||
template <typename T> constexpr
|
||||
auto detail_::FormatterReuseProxy<T>::parse(fmt::format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&fmt::format_parse_context::begin), fmt::format_parse_context>
|
||||
{
|
||||
if (ctx.begin() != ctx.end() && *ctx.begin() != '}')
|
||||
throw fmt::format_error
|
||||
(
|
||||
"{} do not support to be format, so the wrapper should not have any format syntax."_f
|
||||
(nameof::nameof_full_type<T>())
|
||||
);
|
||||
return ctx.begin();
|
||||
}
|
||||
}
|
||||
template <typename T> constexpr
|
||||
auto detail_::FormatterReuseProxy<T>::parse(fmt::format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&fmt::format_parse_context::begin), fmt::format_parse_context>
|
||||
{
|
||||
if (ctx.begin() != ctx.end() && *ctx.begin() != '}')
|
||||
throw fmt::format_error
|
||||
(
|
||||
"{} do not support to be format, so the wrapper should not have any format syntax."_f
|
||||
(nameof::nameof_full_type<T>())
|
||||
);
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <typename Char, typename... Ts> requires (sizeof...(Ts) > 0)
|
||||
basic_ostream<Char>& operator<<(basic_ostream<Char>& os, const variant<Ts...>& value)
|
||||
{
|
||||
using namespace biu::literals;
|
||||
auto try_print = [&]<typename T>
|
||||
{
|
||||
if (holds_alternative<T>(value))
|
||||
{
|
||||
if constexpr (biu::Formattable<T, Char>)
|
||||
os << "({}: {})"_f(nameof::nameof_full_type<T>(), get<T>(value));
|
||||
else
|
||||
os << "({}: {})"_f(nameof::nameof_full_type<T>(), "non-null unformattable value");
|
||||
}
|
||||
};
|
||||
(try_print.template operator()<Ts>(), ...);
|
||||
return os;
|
||||
}
|
||||
template <typename Char, typename... Ts> requires (sizeof...(Ts) > 0) std::basic_ostream<Char>&
|
||||
stream_operators::operator<<(std::basic_ostream<Char>& os, const std::variant<Ts...>& value)
|
||||
{
|
||||
using namespace biu::literals;
|
||||
auto try_print = [&]<typename T>
|
||||
{
|
||||
if (holds_alternative<T>(value))
|
||||
{
|
||||
if constexpr (biu::Formattable<T, Char>) os << "({}: {})"_f(nameof::nameof_full_type<T>(), get<T>(value));
|
||||
else os << "({}: {})"_f(nameof::nameof_full_type<T>(), "non-null unformattable value");
|
||||
}
|
||||
};
|
||||
(try_print.template operator()<Ts>(), ...);
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <typename Char, biu::detail_::OptionalWrap Wrap> template <typename FormatContext>
|
||||
auto formatter<Wrap, Char>::format(const Wrap& wrap, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>
|
||||
{
|
||||
using namespace biu::literals;
|
||||
using namespace biu::stream_operators;
|
||||
using value_t = biu::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type;
|
||||
auto format_value_type = [&, this](const value_t& value)
|
||||
{
|
||||
if constexpr (!biu::Formattable<value_t, Char>)
|
||||
return format_to(ctx.out(), "non-null unformattable value");
|
||||
else if constexpr (std::default_initializable<formatter<value_t>>)
|
||||
biu::detail_::FormatterReuseProxy<value_t>::format(value, ctx);
|
||||
else
|
||||
format_to(ctx.out(), "{}", value);
|
||||
};
|
||||
format_to(ctx.out(), "(");
|
||||
if constexpr (biu::SpecializationOf<Wrap, std::optional>)
|
||||
{
|
||||
if (wrap)
|
||||
format_value_type(*wrap);
|
||||
else
|
||||
format_to(ctx.out(), "null");
|
||||
}
|
||||
else if constexpr (biu::SpecializationOf<Wrap, std::weak_ptr>)
|
||||
{
|
||||
if (auto shared = wrap.lock())
|
||||
{
|
||||
format_to(ctx.out(), "{} ", ptr(shared.get()));
|
||||
format_value_type(*shared);
|
||||
}
|
||||
else
|
||||
format_to(ctx.out(), "null");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wrap)
|
||||
{
|
||||
format_to(ctx.out(), "{} ", ptr(wrap.get()));
|
||||
format_value_type(*wrap);
|
||||
}
|
||||
else
|
||||
format_to(ctx.out(), "null");
|
||||
}
|
||||
return format_to(ctx.out(), ")");
|
||||
}
|
||||
template <typename Char, biu::detail_::OptionalWrap Wrap> template <typename FormatContext>
|
||||
auto formatter<Wrap, Char>::format(const Wrap& wrap, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>
|
||||
{
|
||||
using value_t = biu::detail_::UnderlyingTypeOfOptionalWrap<Wrap>::Type;
|
||||
auto format_value_type = [&, this](const value_t& value)
|
||||
{
|
||||
if constexpr (!biu::Formattable<value_t, Char>) return fmt::format_to(ctx.out(), "non-null unformattable value");
|
||||
else if constexpr (std::default_initializable<formatter<value_t>>)
|
||||
biu::detail_::FormatterReuseProxy<value_t>::format(value, ctx);
|
||||
else fmt::format_to(ctx.out(), "{}", value);
|
||||
};
|
||||
fmt::format_to(ctx.out(), "(");
|
||||
if constexpr (biu::SpecializationOf<Wrap, std::optional>)
|
||||
{ if (wrap) format_value_type(*wrap); else fmt::format_to(ctx.out(), "null"); }
|
||||
else if constexpr (biu::SpecializationOf<Wrap, std::weak_ptr>)
|
||||
{
|
||||
if (auto shared = wrap.lock())
|
||||
{ fmt::format_to(ctx.out(), "{} ", ptr(shared.get())); format_value_type(*shared); }
|
||||
else fmt::format_to(ctx.out(), "null");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wrap) { fmt::format_to(ctx.out(), "{} ", ptr(wrap.get())); format_value_type(*wrap); }
|
||||
else fmt::format_to(ctx.out(), "null");
|
||||
}
|
||||
return fmt::format_to(ctx.out(), ")");
|
||||
}
|
||||
|
||||
template <typename Char, biu::Enumerable T> constexpr
|
||||
auto formatter<T, Char>::parse(format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&format_parse_context::begin), format_parse_context>
|
||||
{
|
||||
auto it = ctx.begin();
|
||||
if (it != ctx.end() && *it == 'f')
|
||||
{
|
||||
full = true;
|
||||
it++;
|
||||
}
|
||||
if (it != ctx.end() && *it != '}')
|
||||
throw format_error{"syntax error."};
|
||||
return it;
|
||||
}
|
||||
template <typename Char, biu::Enumerable T> constexpr auto formatter<T, Char>::parse(format_parse_context& ctx)
|
||||
-> std::invoke_result_t<decltype(&format_parse_context::begin), format_parse_context>
|
||||
{
|
||||
auto it = ctx.begin();
|
||||
if (it != ctx.end() && *it == 'f') { full = true; it++; }
|
||||
if (it != ctx.end() && *it != '}') throw format_error{"syntax error."};
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename Char, biu::Enumerable T> template <typename FormatContext>
|
||||
auto formatter<T, Char>::format(const T& value, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>
|
||||
{
|
||||
if (full)
|
||||
return format_to(ctx.out(), "{}::{}", nameof::nameof_type<T>(), nameof::nameof_enum(value));
|
||||
else
|
||||
return format_to(ctx.out(), "{}", nameof::nameof_enum(value));
|
||||
}
|
||||
template <typename Char, biu::Enumerable T> template <typename FormatContext>
|
||||
auto formatter<T, Char>::format(const T& value, FormatContext& ctx)
|
||||
-> std::invoke_result_t<decltype(&FormatContext::out), FormatContext>
|
||||
{
|
||||
if (full) return fmt::format_to(ctx.out(), "{}::{}", nameof::nameof_type<T>(), nameof::nameof_enum(value));
|
||||
else return fmt::format_to(ctx.out(), "{}", nameof::nameof_enum(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,108 +4,114 @@
|
||||
# include <string>
|
||||
# include <string_view>
|
||||
# include <iostream>
|
||||
# include <concurrencpp/concurrencpp.h>
|
||||
# include <biu/concepts.hpp>
|
||||
# include <biu/smartref.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
// Store a string in a static member of a class; or, use a class to represent a string.
|
||||
template <DecayedType Char, Char... c> struct BasicStaticString
|
||||
{
|
||||
static constexpr std::array<Char, sizeof...(c)> Array{c...};
|
||||
static constexpr std::basic_string_view<Char> StringView{Array.data(), sizeof...(c)};
|
||||
};
|
||||
template <char... c> using StaticString = BasicStaticString<char, c...>;
|
||||
inline namespace stream_operators
|
||||
{
|
||||
template <typename Char, Char... c>
|
||||
std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os, BasicStaticString<Char, c...>);
|
||||
}
|
||||
inline namespace literals
|
||||
{ template <typename Char, Char... c> consteval BasicStaticString<Char, c...> operator""_ss(); }
|
||||
namespace detail_
|
||||
{
|
||||
template <typename C, typename T> struct SpecializationOfBasicStaticStringHelper : std::false_type {};
|
||||
template <typename C, C... c>
|
||||
struct SpecializationOfBasicStaticStringHelper<C, BasicStaticString<C, c...>> : std::true_type {};
|
||||
template <typename C, C... c>
|
||||
struct SpecializationOfBasicStaticStringHelper<void, BasicStaticString<C, c...>> : std::true_type {};
|
||||
template <typename T, typename C> concept SpecializationOfBasicStaticString
|
||||
= SpecializationOfBasicStaticStringHelper<std::decay_t<C>, std::decay_t<T>>::value;
|
||||
}
|
||||
template <typename T, typename C = void> concept SpecializationOfBasicStaticString
|
||||
= detail_::SpecializationOfBasicStaticString<T, C>
|
||||
&& detail_::SpecializationOfBasicStaticString<T, void>;
|
||||
template <typename T> concept SpecializationOfStaticString = SpecializationOfBasicStaticString<T, char>;
|
||||
namespace string
|
||||
{
|
||||
// Store a string in a static member of a class; or, use a class to represent a string.
|
||||
template <DecayedType Char, Char... c> struct BasicStaticString
|
||||
{
|
||||
static constexpr std::array<Char, sizeof...(c)> Array{c...};
|
||||
static constexpr std::basic_string_view<Char> StringView{Array.data(), sizeof...(c)};
|
||||
};
|
||||
template <char... c> using StaticString = BasicStaticString<char, c...>;
|
||||
|
||||
// Store a string in a fixed-size array
|
||||
template <DecayedType Char, std::size_t N> struct BasicFixedString
|
||||
{
|
||||
Char Data[N];
|
||||
constexpr static const std::size_t Size = N - 1;
|
||||
constexpr BasicFixedString(const Char (&str)[N]);
|
||||
};
|
||||
template <std::size_t N> using FixedString = BasicFixedString<char, N>;
|
||||
inline namespace stream_operators
|
||||
{
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicFixedString<Char, N>& str);
|
||||
}
|
||||
inline namespace literals { template <BasicFixedString FS> constexpr decltype(FS) operator""_fs(); }
|
||||
namespace detail_
|
||||
{
|
||||
template <typename C, typename T> struct SpecializationOfBasicFixedStringHelper : std::false_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicFixedStringHelper<C, BasicFixedString<C, N>> : std::true_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicFixedStringHelper<void, BasicFixedString<C, N>> : std::true_type {};
|
||||
template <typename T, typename C> concept SpecializationOfBasicFixedString
|
||||
= SpecializationOfBasicFixedStringHelper<std::decay_t<C>, std::decay_t<T>>::value;
|
||||
}
|
||||
template <typename T, typename C = void> concept SpecializationOfBasicFixedString
|
||||
= detail_::SpecializationOfBasicFixedString<T, C>
|
||||
&& detail_::SpecializationOfBasicFixedString<T, void>;
|
||||
template <typename T> concept SpecializationOfFixedString = SpecializationOfBasicFixedString<T, char>;
|
||||
// Store a string in a fixed-size array
|
||||
template <DecayedType Char, std::size_t N> struct BasicFixedString
|
||||
{
|
||||
Char Data[N];
|
||||
constexpr static const std::size_t Size = N - 1;
|
||||
constexpr BasicFixedString(const Char (&str)[N]);
|
||||
};
|
||||
template <std::size_t N> using FixedString = BasicFixedString<char, N>;
|
||||
|
||||
// Store a string with at most N characters
|
||||
template <DecayedType Char, std::size_t N> struct BasicVariableString
|
||||
{
|
||||
Char Data[N];
|
||||
std::size_t Size;
|
||||
constexpr static const std::size_t MaxSize = N - 1;
|
||||
template <std::size_t M> requires (M<=N) constexpr BasicVariableString(const Char (&str)[M]);
|
||||
};
|
||||
template <std::size_t N> using VariableString = BasicVariableString<char, N>;
|
||||
inline namespace stream_operators
|
||||
{
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicVariableString<Char, N>& str);
|
||||
}
|
||||
// Store a string with at most N characters
|
||||
template <DecayedType Char, std::size_t N> struct BasicVariableString
|
||||
{
|
||||
Char Data[N];
|
||||
std::size_t Size;
|
||||
constexpr static const std::size_t MaxSize = N - 1;
|
||||
template <std::size_t M> requires (M<=N) constexpr BasicVariableString(const Char (&str)[M]);
|
||||
};
|
||||
template <std::size_t N> using VariableString = BasicVariableString<char, N>;
|
||||
}
|
||||
using string::BasicStaticString, string::StaticString, string::BasicFixedString, string::FixedString,
|
||||
string::BasicVariableString, string::VariableString;
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename C, typename T> struct SpecializationOfBasicVariableStringHelper : std::false_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicVariableStringHelper<C, BasicVariableString<C, N>> : std::true_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicVariableStringHelper<void, BasicVariableString<C, N>> : std::true_type {};
|
||||
template <typename T, typename C> concept SpecializationOfBasicVariableString
|
||||
= SpecializationOfBasicVariableStringHelper<std::decay_t<C>, std::decay_t<T>>::value;
|
||||
}
|
||||
template <typename T, typename C = void> concept SpecializationOfBasicVariableString
|
||||
= detail_::SpecializationOfBasicVariableString<T, C>
|
||||
&& detail_::SpecializationOfBasicVariableString<T, void>;
|
||||
template <typename T> concept SpecializationOfVariableString = SpecializationOfBasicVariableString<T, char>;
|
||||
inline namespace stream_operators
|
||||
{
|
||||
template <typename Char, Char... c>
|
||||
std::basic_ostream<Char>& operator<<(std::basic_ostream<Char>& os, BasicStaticString<Char, c...>);
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicFixedString<Char, N>& str);
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicVariableString<Char, N>& str);
|
||||
}
|
||||
inline namespace literals
|
||||
{
|
||||
template <typename Char, Char... c> consteval BasicStaticString<Char, c...> operator""_ss();
|
||||
template <BasicFixedString FS> constexpr decltype(FS) operator""_fs();
|
||||
}
|
||||
namespace concepts
|
||||
{
|
||||
namespace detail_
|
||||
{
|
||||
template <typename C, typename T> struct SpecializationOfBasicStaticStringHelper : std::false_type {};
|
||||
template <typename C, C... c>
|
||||
struct SpecializationOfBasicStaticStringHelper<C, BasicStaticString<C, c...>> : std::true_type {};
|
||||
template <typename C, C... c>
|
||||
struct SpecializationOfBasicStaticStringHelper<void, BasicStaticString<C, c...>> : std::true_type {};
|
||||
template <typename T, typename C> concept SpecializationOfBasicStaticString
|
||||
= SpecializationOfBasicStaticStringHelper<std::decay_t<C>, std::decay_t<T>>::value;
|
||||
}
|
||||
template <typename T, typename C = void> concept SpecializationOfBasicStaticString
|
||||
= detail_::SpecializationOfBasicStaticString<T, C>
|
||||
&& detail_::SpecializationOfBasicStaticString<T, void>;
|
||||
template <typename T> concept SpecializationOfStaticString = SpecializationOfBasicStaticString<T, char>;
|
||||
|
||||
namespace string
|
||||
{
|
||||
// Find specific content in a string. Return unmatched content before the match and the match result every
|
||||
// time. If match reached the end, the second returned value will be std::sregex_iterator().
|
||||
concurrencpp::generator<std::pair<std::string_view, std::sregex_iterator>> find
|
||||
(SmartRef<const std::string> data, SmartRef<const std::regex> regex);
|
||||
// Use a regex to find all matches and replace them with a callback function
|
||||
std::string replace
|
||||
(const std::string& data, const std::regex& regex, std::function<std::string(const std::smatch&)> function);
|
||||
}
|
||||
namespace detail_
|
||||
{
|
||||
template <typename C, typename T> struct SpecializationOfBasicFixedStringHelper : std::false_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicFixedStringHelper<C, BasicFixedString<C, N>> : std::true_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicFixedStringHelper<void, BasicFixedString<C, N>> : std::true_type {};
|
||||
template <typename T, typename C> concept SpecializationOfBasicFixedString
|
||||
= SpecializationOfBasicFixedStringHelper<std::decay_t<C>, std::decay_t<T>>::value;
|
||||
}
|
||||
template <typename T, typename C = void> concept SpecializationOfBasicFixedString
|
||||
= detail_::SpecializationOfBasicFixedString<T, C>
|
||||
&& detail_::SpecializationOfBasicFixedString<T, void>;
|
||||
template <typename T> concept SpecializationOfFixedString = SpecializationOfBasicFixedString<T, char>;
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename C, typename T> struct SpecializationOfBasicVariableStringHelper : std::false_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicVariableStringHelper<C, BasicVariableString<C, N>> : std::true_type {};
|
||||
template <typename C, std::size_t N>
|
||||
struct SpecializationOfBasicVariableStringHelper<void, BasicVariableString<C, N>> : std::true_type {};
|
||||
template <typename T, typename C> concept SpecializationOfBasicVariableString
|
||||
= SpecializationOfBasicVariableStringHelper<std::decay_t<C>, std::decay_t<T>>::value;
|
||||
}
|
||||
template <typename T, typename C = void> concept SpecializationOfBasicVariableString
|
||||
= detail_::SpecializationOfBasicVariableString<T, C>
|
||||
&& detail_::SpecializationOfBasicVariableString<T, void>;
|
||||
template <typename T> concept SpecializationOfVariableString = SpecializationOfBasicVariableString<T, char>;
|
||||
}
|
||||
using concepts::SpecializationOfBasicStaticString, concepts::SpecializationOfStaticString,
|
||||
concepts::SpecializationOfBasicFixedString, concepts::SpecializationOfFixedString,
|
||||
concepts::SpecializationOfBasicVariableString, concepts::SpecializationOfVariableString;
|
||||
}
|
||||
// namespace string
|
||||
// {
|
||||
// // Find specific content in a string. Return unmatched content before the match and the match result every
|
||||
// // time. If match reached the end, the second returned value will be std::sregex_iterator().
|
||||
// concurrencpp::generator<std::pair<std::string_view, std::sregex_iterator>> find
|
||||
// (SmartRef<const std::string> data, SmartRef<const std::regex> regex);
|
||||
// // Use a regex to find all matches and replace them with a callback function
|
||||
// std::string replace
|
||||
// (const std::string& data, const std::regex& regex, std::function<std::string(const std::smatch&)> function);
|
||||
// }
|
||||
|
||||
@@ -3,28 +3,37 @@
|
||||
|
||||
namespace biu
|
||||
{
|
||||
template <typename Char, Char... c> inline std::basic_ostream<Char>& stream_operators::operator<<
|
||||
(std::basic_ostream<Char>& os, BasicStaticString<Char, c...>)
|
||||
{ return os << std::basic_string_view{c...}; }
|
||||
template <typename Char, Char... c> consteval BasicStaticString<Char, c...> literals::operator""_ss()
|
||||
{ return {}; }
|
||||
namespace string
|
||||
{
|
||||
template <DecayedType Char, std::size_t N> constexpr
|
||||
BasicFixedString<Char, N>::BasicFixedString(const Char (&str)[N])
|
||||
{ std::copy_n(str, N, Data); }
|
||||
template <DecayedType Char, std::size_t N> template <std::size_t M> requires (M<=N) constexpr
|
||||
BasicVariableString<Char, N>::BasicVariableString(const Char (&str)[M]) : Size(M)
|
||||
{
|
||||
std::fill(Data, Data + N, '\0');
|
||||
std::copy_n(str, M, Data);
|
||||
}
|
||||
}
|
||||
|
||||
template <DecayedType Char, std::size_t N> constexpr
|
||||
BasicFixedString<Char, N>::BasicFixedString(const Char (&str)[N])
|
||||
{ std::copy_n(str, N, Data); }
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& stream_operators::operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicFixedString<Char, N>& str)
|
||||
{ return os << std::basic_string_view<Char>(str.Data, str.Size); }
|
||||
template <BasicFixedString FS> constexpr decltype(FS) literals::operator""_fs()
|
||||
{ return FS; }
|
||||
inline namespace stream_operators
|
||||
{
|
||||
template <typename Char, Char... c> inline std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, BasicStaticString<Char, c...>)
|
||||
{ return os << std::basic_string_view{c...}; }
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicFixedString<Char, N>& str)
|
||||
{ return os << std::basic_string_view<Char>(str.Data, str.Size); }
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicVariableString<Char, N>& str)
|
||||
{ return os << std::basic_string_view<Char>(str.Data, str.Size); }
|
||||
}
|
||||
|
||||
template <DecayedType Char, std::size_t N> template <std::size_t M> requires (M<=N) constexpr
|
||||
BasicVariableString<Char, N>::BasicVariableString(const Char (&str)[M]) : Size(M)
|
||||
{
|
||||
std::fill(Data, Data + N, '\0');
|
||||
std::copy_n(str, M, Data);
|
||||
}
|
||||
template <typename Char, std::size_t N> std::basic_ostream<Char>& stream_operators::operator<<
|
||||
(std::basic_ostream<Char>& os, const BasicVariableString<Char, N>& str)
|
||||
{ return os << std::basic_string_view<Char>(str.Data, str.Size); }
|
||||
inline namespace literals
|
||||
{
|
||||
template <typename Char, Char... c> consteval BasicStaticString<Char, c...> operator""_ss()
|
||||
{ return {}; }
|
||||
template <BasicFixedString FS> constexpr decltype(FS) operator""_fs()
|
||||
{ return FS; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,104 @@
|
||||
# include <future>
|
||||
# include <utility>
|
||||
# include <cstdio>
|
||||
# include <biu.hpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <boost/preprocessor.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
std::regex literals::operator""_re(const char* str, std::size_t len)
|
||||
{ return std::regex{str, len}; }
|
||||
void block_forever()
|
||||
{
|
||||
std::promise<void>().get_future().wait();
|
||||
std::unreachable();
|
||||
}
|
||||
std::regex literals::operator""_re(const char* str, std::size_t len) { return std::regex{str, len}; }
|
||||
namespace common
|
||||
{
|
||||
void block_forever() { std::promise<void>().get_future().wait(); std::unreachable(); }
|
||||
bool is_interactive() { return isatty(fileno(stdin)); }
|
||||
std::optional<std::string> env(std::string name)
|
||||
{
|
||||
if (auto value = std::getenv(name.c_str()); !value) return std::nullopt;
|
||||
else return value;
|
||||
}
|
||||
|
||||
template <bool DirectStdout, bool DirectStderr>
|
||||
detail_::ExecResult<DirectStdout, DirectStderr>::operator bool() const
|
||||
{ return ExitCode == 0; }
|
||||
# define BIU_EXECRESULT_PRED(r, state) BOOST_PP_NOT_EQUAL(state, 4)
|
||||
# define BIU_EXECRESULT_OP(r, state) BOOST_PP_INC(state)
|
||||
# define BIU_EXECRESULT_MACRO(r, state) \
|
||||
template detail_::ExecResult<(state & 1) != 0, (state & 2) != 0>::operator bool() const;
|
||||
BOOST_PP_FOR(0, BIU_EXECRESULT_PRED, BIU_EXECRESULT_OP, BIU_EXECRESULT_MACRO)
|
||||
namespace detail_
|
||||
{
|
||||
template <ExecInput Input>
|
||||
detail_::ExecResult<Input.DirectStdout, Input.DirectStderr> exec
|
||||
(
|
||||
std::conditional_t<Input.SearchPath, std::string, std::filesystem::path> program, std::vector<std::string> args,
|
||||
std::optional<std::string> stdin_string, std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{
|
||||
namespace bp = boost::process;
|
||||
bp::ipstream stdout_stream, stderr_stream;
|
||||
bp::opstream input_stream;
|
||||
auto&& stdout_format = [&]
|
||||
{ if constexpr (Input.DirectStdout) return bp::std_out > stdout; else return bp::std_out > stdout_stream; }();
|
||||
auto&& stderr_format = [&]
|
||||
{ if constexpr (Input.DirectStderr) return bp::std_err > stderr; else return bp::std_err > stderr_stream; }();
|
||||
auto&& actual_program =
|
||||
[&]{ if constexpr (Input.SearchPath) return bp::search_path(program); else return program.string(); }();
|
||||
std::unique_ptr<bp::child> process;
|
||||
bp::environment env = boost::this_process::environment();
|
||||
for (const auto& [key, value] : extra_env) env[key] = value;
|
||||
process = [&]
|
||||
{
|
||||
if constexpr (Input.DirectStdin) return std::make_unique<bp::child>
|
||||
(actual_program, bp::args(args), stdout_format, stderr_format, bp::std_in < stdin, env);
|
||||
else if (stdin_string) return std::make_unique<bp::child>
|
||||
(actual_program, bp::args(args), stdout_format, stderr_format, bp::std_in < input_stream, env);
|
||||
else return std::make_unique<bp::child>
|
||||
(actual_program, bp::args(args), stdout_format, stderr_format, bp::std_in < bp::null, env);
|
||||
}();
|
||||
if (stdin_string) { input_stream << *stdin_string; input_stream.pipe().close(); }
|
||||
process->wait();
|
||||
return
|
||||
{
|
||||
.ExitCode = process->exit_code(),
|
||||
.Stdout = [&]
|
||||
{
|
||||
if constexpr (Input.DirectStdout) return Empty{};
|
||||
else return std::string{std::istreambuf_iterator<char>{stdout_stream.rdbuf()}, {}};
|
||||
}(),
|
||||
.Stderr = [&]
|
||||
{
|
||||
if constexpr (Input.DirectStderr) return Empty{};
|
||||
else return std::string{std::istreambuf_iterator<char>{stderr_stream.rdbuf()}, {}};
|
||||
}()
|
||||
};
|
||||
}
|
||||
}
|
||||
template <detail_::ExecInput Input> requires (!Input.DirectStdin)
|
||||
detail_::ExecResult<Input.DirectStdout, Input.DirectStderr> exec
|
||||
(
|
||||
std::conditional_t<Input.SearchPath, std::string, std::filesystem::path> program, std::vector<std::string> args,
|
||||
std::optional<std::string> stdin_string, std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{ return detail_::exec<Input>(program, args, stdin_string, extra_env); }
|
||||
template <detail_::ExecInput Input> requires (Input.DirectStdin)
|
||||
detail_::ExecResult<Input.DirectStdout, Input.DirectStderr> exec
|
||||
(
|
||||
std::conditional_t<Input.SearchPath, std::string, std::filesystem::path> program, std::vector<std::string> args,
|
||||
std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{ return detail_::exec<Input>(program, args, {}, extra_env); }
|
||||
# define BIU_EXEC_PRED(r, state) BOOST_PP_NOT_EQUAL(state, 8)
|
||||
# define BIU_EXEC_OP(r, state) BOOST_PP_INC(state)
|
||||
# define BIU_EXEC_MACRO(r, state) \
|
||||
template detail_::ExecResult<(state & 1) != 0, (state & 2) != 0> \
|
||||
exec<{false, (state & 1) != 0, (state & 2) != 0, (state & 4) != 0}> \
|
||||
(std::conditional_t<(state & 4) != 0, std::string, std::filesystem::path>, std::vector<std::string>, \
|
||||
std::optional<std::string>, std::map<std::string, std::string>); \
|
||||
template detail_::ExecResult<(state & 1) != 0, (state & 2) != 0> \
|
||||
exec<{true, (state & 1) != 0, (state & 2) != 0, (state & 4) != 0}> \
|
||||
(std::conditional_t<(state & 4) != 0, std::string, std::filesystem::path>, std::vector<std::string>, \
|
||||
std::map<std::string, std::string>);
|
||||
BOOST_PP_FOR(0, BIU_EXEC_PRED, BIU_EXEC_OP, BIU_EXEC_MACRO)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,51 +3,51 @@
|
||||
|
||||
namespace biu
|
||||
{
|
||||
concurrencpp::generator<std::pair<std::string_view, std::sregex_iterator>> string::find
|
||||
(SmartRef<const std::string> data, SmartRef<const std::regex> regex)
|
||||
{
|
||||
Logger::Guard log;
|
||||
std::string::const_iterator unmatched_prefix_begin = data->cbegin(), unmatched_prefix_end;
|
||||
std::sregex_iterator regit;
|
||||
while (true)
|
||||
{
|
||||
if (regit == std::sregex_iterator{})
|
||||
regit = std::sregex_iterator{data->begin(), data->end(), *regex};
|
||||
else
|
||||
regit++;
|
||||
if (regit == std::sregex_iterator{})
|
||||
{
|
||||
unmatched_prefix_end = data->cend();
|
||||
log.log<Logger::Level::Debug>("distance: {}"_f(std::distance(unmatched_prefix_begin, unmatched_prefix_end)));
|
||||
}
|
||||
else
|
||||
unmatched_prefix_end = (*regit)[0].first;
|
||||
co_yield
|
||||
{
|
||||
std::string_view
|
||||
{
|
||||
&*unmatched_prefix_begin,
|
||||
static_cast<std::size_t>(std::distance(unmatched_prefix_begin, unmatched_prefix_end))
|
||||
},
|
||||
regit
|
||||
};
|
||||
if (regit == std::sregex_iterator{})
|
||||
break;
|
||||
unmatched_prefix_begin = (*regit)[0].second;
|
||||
}
|
||||
}
|
||||
concurrencpp::generator<std::pair<std::string_view, std::sregex_iterator>> string::find
|
||||
(SmartRef<const std::string> data, SmartRef<const std::regex> regex)
|
||||
{
|
||||
Logger::Guard log;
|
||||
std::string::const_iterator unmatched_prefix_begin = data->cbegin(), unmatched_prefix_end;
|
||||
std::sregex_iterator regit;
|
||||
while (true)
|
||||
{
|
||||
if (regit == std::sregex_iterator{})
|
||||
regit = std::sregex_iterator{data->begin(), data->end(), *regex};
|
||||
else
|
||||
regit++;
|
||||
if (regit == std::sregex_iterator{})
|
||||
{
|
||||
unmatched_prefix_end = data->cend();
|
||||
log.log<Logger::Level::Debug>("distance: {}"_f(std::distance(unmatched_prefix_begin, unmatched_prefix_end)));
|
||||
}
|
||||
else
|
||||
unmatched_prefix_end = (*regit)[0].first;
|
||||
co_yield
|
||||
{
|
||||
std::string_view
|
||||
{
|
||||
&*unmatched_prefix_begin,
|
||||
static_cast<std::size_t>(std::distance(unmatched_prefix_begin, unmatched_prefix_end))
|
||||
},
|
||||
regit
|
||||
};
|
||||
if (regit == std::sregex_iterator{})
|
||||
break;
|
||||
unmatched_prefix_begin = (*regit)[0].second;
|
||||
}
|
||||
}
|
||||
|
||||
std::string string::replace
|
||||
(const std::string& data, const std::regex& regex, std::function<std::string(const std::smatch&)> function)
|
||||
{
|
||||
Logger::Guard log;
|
||||
std::string result;
|
||||
for (auto matched : find(data, regex))
|
||||
{
|
||||
result.append(matched.first);
|
||||
if (matched.second != std::sregex_iterator{})
|
||||
result.append(function(*matched.second));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::string string::replace
|
||||
(const std::string& data, const std::regex& regex, std::function<std::string(const std::smatch&)> function)
|
||||
{
|
||||
Logger::Guard log;
|
||||
std::string result;
|
||||
for (auto matched : find(data, regex))
|
||||
{
|
||||
result.append(matched.first);
|
||||
if (matched.second != std::sregex_iterator{})
|
||||
result.append(function(*matched.second));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
phases = [ "installPhase" ];
|
||||
installPhase =
|
||||
''
|
||||
mkdir -p $out/share/plasma/wallpapers/a2n.blur
|
||||
cp -r $src/* $out/share/plasma/wallpapers/a2n.blur
|
||||
mkdir -p $out/share/plasma/wallpapers
|
||||
cp -r $src/a2n.blur $out/share/plasma/wallpapers
|
||||
'';
|
||||
}
|
||||
26
local/pkgs/chn-bsub/CMakeLists.txt
Normal file
26
local/pkgs/chn-bsub/CMakeLists.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(chn-bsub VERSION 0.0.0 LANGUAGES CXX)
|
||||
enable_testing()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message("Setting build type to 'Release' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
find_package(ftxui REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem iostreams)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_package(biu REQUIRED)
|
||||
|
||||
add_executable(chn-bsub src/main.cpp)
|
||||
target_compile_features(chn-bsub PUBLIC cxx_std_23)
|
||||
target_link_libraries(chn-bsub PRIVATE fmt::fmt ftxui::screen ftxui::dom ftxui::component Boost::filesystem
|
||||
range-v3::range-v3 biu::biu)
|
||||
|
||||
install(TARGETS chn-bsub RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS)
|
||||
message("Imported targets: ${ImportedTargets}")
|
||||
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
|
||||
12
local/pkgs/chn-bsub/default.nix
Normal file
12
local/pkgs/chn-bsub/default.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
stdenv, lib, sbatchConfig ? null, substituteAll, runCommand,
|
||||
cmake, pkg-config, ftxui, biu
|
||||
}:
|
||||
stdenv.mkDerivation
|
||||
{
|
||||
name = "chn-bsub";
|
||||
src = ./.;
|
||||
buildInputs = [ ftxui biu ];
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
postInstall = "ln -s chn-bsub $out/bin/chn_bsub";
|
||||
}
|
||||
202
local/pkgs/chn-bsub/src/main.cpp
Normal file
202
local/pkgs/chn-bsub/src/main.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
# include <map>
|
||||
# include <filesystem>
|
||||
# include <ftxui/component/component.hpp>
|
||||
# include <ftxui/component/component_options.hpp>
|
||||
# include <ftxui/component/screen_interactive.hpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <boost/algorithm/string.hpp>
|
||||
# include <biu.hpp>
|
||||
|
||||
using namespace biu::literals;
|
||||
|
||||
int main()
|
||||
{
|
||||
// 需要绑定到界面上的变量
|
||||
struct
|
||||
{
|
||||
std::array<int, 3> vasp_version_selected = {0, 0, 0};
|
||||
std::vector<std::string> vasp_version_entries_level1 = {"640", "631"};
|
||||
std::map<std::string, std::vector<std::string>> vasp_version_entries_level2 =
|
||||
{
|
||||
{"640", {"(default)", "fixc", "optcell_vtst_wannier90", "shmem", "vtst"}},
|
||||
{"631", {"shmem"}}
|
||||
};
|
||||
std::vector<std::string> vasp_version_entries_level3 = {"std", "gam", "ncl"};
|
||||
|
||||
int queue_selected = 0;
|
||||
std::vector<std::string> queue_entries =
|
||||
{
|
||||
"normal_1day", "normal_1week", "normal",
|
||||
"normal_1day_new", "ocean_530_1day", "ocean6226R_1day"
|
||||
};
|
||||
std::map<std::string, std::size_t> max_cores =
|
||||
{
|
||||
{"normal_1day", 28}, {"normal_1week", 28}, {"normal", 20},
|
||||
{"normal_1day_new", 24}, {"ocean_530_1day", 24}, {"ocean6226R_1day", 32}
|
||||
};
|
||||
std::string ncores = "";
|
||||
std::string job_name = []
|
||||
{
|
||||
// /data/gpfs01/jykang/linwei/chn/lammps-SiC
|
||||
std::vector<std::string> paths;
|
||||
boost::split(paths, std::filesystem::current_path().string(),
|
||||
boost::is_any_of("/"));
|
||||
if (paths.size() < 7)
|
||||
return "my-great-job"s;
|
||||
else
|
||||
return paths[5] + "_" + paths.back();
|
||||
}();
|
||||
std::string bsub = "";
|
||||
std::string user_command = "";
|
||||
} state;
|
||||
|
||||
// 为组件增加标题栏
|
||||
auto component_with_title = [](std::string title, ftxui::Component component)
|
||||
{
|
||||
return ftxui::Renderer(component, [title, component]
|
||||
{
|
||||
return ftxui::vbox
|
||||
({
|
||||
ftxui::text(title) | ftxui::bgcolor(ftxui::Color::Blue),
|
||||
component->Render(),
|
||||
ftxui::separator()
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 构建界面, 需要至少 25 行 47 列
|
||||
auto screen = ftxui::ScreenInteractive::Fullscreen();
|
||||
auto request_interface = [&state, &screen, &component_with_title]
|
||||
{
|
||||
auto vasp_version_level1 = ftxui::Menu
|
||||
(&state.vasp_version_entries_level1, &state.vasp_version_selected[0])
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 8);
|
||||
std::vector<ftxui::Component> vasp_version_level2_children;
|
||||
for (auto& i : state.vasp_version_entries_level1)
|
||||
vasp_version_level2_children.push_back(ftxui::Menu
|
||||
(
|
||||
&state.vasp_version_entries_level2[i],
|
||||
&state.vasp_version_selected[1]
|
||||
));
|
||||
auto vasp_version_level2 = ftxui::Container::Tab
|
||||
(
|
||||
vasp_version_level2_children,
|
||||
&state.vasp_version_selected[0]
|
||||
) | ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 27);
|
||||
auto vasp_version_level3 = ftxui::Menu
|
||||
(&state.vasp_version_entries_level3, &state.vasp_version_selected[2])
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 8);
|
||||
auto vasp_version = component_with_title("Select vasp version:",
|
||||
ftxui::Container::Horizontal
|
||||
({vasp_version_level1, vasp_version_level2, vasp_version_level3})
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 5));
|
||||
auto queue = component_with_title("Select queue:",
|
||||
ftxui::Menu(&state.queue_entries, &state.queue_selected)
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 6));
|
||||
auto ncores = component_with_title("Input cores you want to use:",
|
||||
ftxui::Input(&state.ncores, "(leave blank to use all cores)"))
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 3);
|
||||
auto job_name = component_with_title("Job name:",
|
||||
ftxui::Input(&state.job_name, ""))
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 3);
|
||||
auto continue_button = ftxui::Button("Continue",
|
||||
[&]{state.user_command = "continue"; screen.ExitLoopClosure()();});
|
||||
auto quit_button = ftxui::Button("Quit",
|
||||
[&]{state.user_command = "quit"; screen.ExitLoopClosure()();});
|
||||
return ftxui::Container::Vertical
|
||||
({
|
||||
vasp_version, queue, ncores, job_name,
|
||||
ftxui::Container::Horizontal({continue_button, quit_button})
|
||||
}) | ftxui::borderHeavy
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 47)
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 24);
|
||||
}();
|
||||
auto confirm_interface = [&state, &screen, &component_with_title]
|
||||
{
|
||||
ftxui::InputOption input_option;
|
||||
input_option.multiline = true;
|
||||
return ftxui::Container::Vertical
|
||||
({
|
||||
component_with_title
|
||||
(
|
||||
"Double check & modify submit command:",
|
||||
ftxui::Input(&state.bsub, "", input_option)
|
||||
)
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 7),
|
||||
ftxui::Container::Horizontal
|
||||
({
|
||||
ftxui::Button("Submit",
|
||||
[&]{state.user_command = "submit"; screen.ExitLoopClosure()();}),
|
||||
ftxui::Button("Quit",
|
||||
[&]{state.user_command = "quit"; screen.ExitLoopClosure()();}),
|
||||
ftxui::Button("Back",
|
||||
[&]{state.user_command = "back"; screen.ExitLoopClosure()();})
|
||||
}),
|
||||
ftxui::Renderer([]{return ftxui::vbox
|
||||
({
|
||||
ftxui::separator(),
|
||||
ftxui::text("Source code:"),
|
||||
ftxui::text("https://github.com/CHN-beta/chn_bsub.git"),
|
||||
ftxui::text("Star & PR are welcome!"),
|
||||
});})
|
||||
}) | ftxui::borderHeavy
|
||||
| ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 47)
|
||||
| ftxui::size(ftxui::HEIGHT, ftxui::EQUAL, 14);
|
||||
}();
|
||||
|
||||
// 实际投递任务
|
||||
auto submit = [](std::string bsub)
|
||||
{
|
||||
// replace \n with space
|
||||
boost::replace_all(bsub, "\n", " ");
|
||||
auto process = boost::process::child
|
||||
(
|
||||
boost::process::search_path("sh"), "-c", bsub,
|
||||
boost::process::std_in.close(),
|
||||
boost::process::std_out > stdout,
|
||||
boost::process::std_err > stderr
|
||||
);
|
||||
process.wait();
|
||||
};
|
||||
|
||||
// 进入事件循环
|
||||
while (true)
|
||||
{
|
||||
screen.Loop(request_interface);
|
||||
if (state.user_command == "quit")
|
||||
return EXIT_FAILURE;
|
||||
else if (state.user_command != "continue")
|
||||
throw std::runtime_error("user_command is not recognized");
|
||||
state.bsub = fmt::format
|
||||
(
|
||||
"bsub -J '{}'\n-q {}\n-n {}\n-R 'span[hosts=1]'\n-o 'output.txt'\nchn_vasp.sh {}",
|
||||
state.job_name,
|
||||
state.queue_entries[state.queue_selected],
|
||||
state.ncores.empty() ? state.max_cores[state.queue_entries[state.queue_selected]] :
|
||||
std::stoi(state.ncores),
|
||||
[&]
|
||||
{
|
||||
auto version_level1 = state.vasp_version_entries_level1[state.vasp_version_selected[0]];
|
||||
auto version_level2 = state.vasp_version_entries_level2[version_level1]
|
||||
[state.vasp_version_selected[1]];
|
||||
auto version_level3 = state.vasp_version_entries_level3[state.vasp_version_selected[2]];
|
||||
return fmt::format
|
||||
(
|
||||
"{}{}_{}",
|
||||
version_level1,
|
||||
version_level2 == "(default)" ? ""s : "_" + version_level2,
|
||||
version_level3
|
||||
);
|
||||
}()
|
||||
);
|
||||
screen.Loop(confirm_interface);
|
||||
if (state.user_command == "quit")
|
||||
return EXIT_FAILURE;
|
||||
else if (state.user_command == "back")
|
||||
continue;
|
||||
else if (state.user_command != "submit")
|
||||
throw std::runtime_error("user_command is not recognized");
|
||||
submit(state.bsub);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,14 @@ inputs: rec
|
||||
{
|
||||
typora = inputs.pkgs.callPackage ./typora {};
|
||||
vesta = inputs.pkgs.callPackage ./vesta {};
|
||||
rsshub = inputs.pkgs.callPackage ./rsshub.nix { inherit mkPnpmPackage; src = inputs.topInputs.rsshub; };
|
||||
misskey = inputs.pkgs.callPackage ./misskey.nix { inherit mkPnpmPackage; src = inputs.topInputs.misskey; };
|
||||
rsshub = inputs.pkgs.callPackage ./rsshub.nix
|
||||
{
|
||||
inherit mkPnpmPackage;
|
||||
src = inputs.topInputs.rsshub;
|
||||
nodejs = nodejs-with-pnpm9.override { nodejs = inputs.pkgs.nodejs_22; };
|
||||
};
|
||||
misskey = inputs.pkgs.callPackage ./misskey.nix
|
||||
{ inherit mkPnpmPackage; src = inputs.topInputs.misskey; nodejs = nodejs-with-pnpm9; };
|
||||
mk-meili-mgn = inputs.pkgs.callPackage ./mk-meili-mgn {};
|
||||
vaspkit = inputs.pkgs.callPackage ./vaspkit { inherit (inputs.localLib) attrsToList; };
|
||||
v-sim = inputs.pkgs.callPackage ./v-sim { src = inputs.topInputs.v-sim; };
|
||||
@@ -24,7 +30,8 @@ inputs: rec
|
||||
{
|
||||
inherit cppcoro nameof tgbot-cpp date;
|
||||
nghttp2 = inputs.pkgs.callPackage "${inputs.topInputs."nixpkgs-23.05"}/pkgs/development/libraries/nghttp2"
|
||||
{ enableAsioLib = true; };
|
||||
{ enableAsioLib = true; stdenv = inputs.pkgs.gcc12Stdenv; };
|
||||
stdenv = inputs.pkgs.gcc12Stdenv;
|
||||
};
|
||||
cppcoro = inputs.pkgs.callPackage ./cppcoro { src = inputs.topInputs.cppcoro; };
|
||||
date = inputs.pkgs.callPackage ./date { src = inputs.topInputs.date; };
|
||||
@@ -35,7 +42,7 @@ inputs: rec
|
||||
torchtext = inputs.pkgs.python3Packages.callPackage ./torchtext { inherit torchdata; };
|
||||
win11os-kde = inputs.pkgs.callPackage ./win11os-kde { src = inputs.topInputs.win11os-kde; };
|
||||
fluent-kde = inputs.pkgs.callPackage ./fluent-kde { src = inputs.topInputs.fluent-kde; };
|
||||
blurred-wallpaper = inputs.pkgs.callPackage ./blurred-wallpaper { src = inputs.topInputs.blurred-wallpaper; };
|
||||
blurred-wallpaper = inputs.pkgs.callPackage ./blurred-wallpaper.nix { src = inputs.topInputs.blurred-wallpaper; };
|
||||
slate = inputs.pkgs.callPackage ./slate { src = inputs.topInputs.slate; };
|
||||
nvhpc = inputs.pkgs.callPackage ./nvhpc {};
|
||||
lmod = inputs.pkgs.callPackage ./lmod { src = inputs.topInputs.lmod; };
|
||||
@@ -64,12 +71,17 @@ inputs: rec
|
||||
mumax = inputs.pkgs.callPackage ./mumax { src = inputs.topInputs.mumax; };
|
||||
kylin-virtual-keyboard = inputs.pkgs.libsForQt5.callPackage ./kylin-virtual-keyboard
|
||||
{ src = inputs.topInputs.kylin-virtual-keyboard; };
|
||||
biu = inputs.pkgs.callPackage ./biu { inherit nameof; };
|
||||
biu = inputs.pkgs.callPackage ./biu { inherit nameof zpp-bits; };
|
||||
zxorm = inputs.pkgs.callPackage ./zxorm { src = inputs.topInputs.zxorm; };
|
||||
hpcstat = inputs.pkgs.callPackage ./hpcstat { inherit nameof sqlite-orm zpp-bits date openxlsx; };
|
||||
hpcstat = inputs.pkgs.callPackage ./hpcstat { inherit nameof sqlite-orm zpp-bits date biu; };
|
||||
openxlsx = inputs.pkgs.callPackage ./openxlsx { src = inputs.topInputs.openxlsx; };
|
||||
sqlite-orm = inputs.pkgs.callPackage ./sqlite-orm { src = inputs.topInputs.sqlite-orm; };
|
||||
mkPnpmPackage = inputs.pkgs.callPackage ./mkPnpmPackage.nix {};
|
||||
nodejs-with-pnpm9 = inputs.pkgs.callPackage ./nodejs-with-pnpm9.nix {};
|
||||
sbatch-tui = inputs.pkgs.callPackage ./sbatch-tui { inherit biu; };
|
||||
ufo = inputs.pkgs.callPackage ./ufo
|
||||
{ inherit concurrencpp biu glad matplotplusplus zpp-bits; tbb = inputs.pkgs.tbb_2021_11; };
|
||||
chn-bsub = inputs.pkgs.callPackage ./chn-bsub { inherit biu; };
|
||||
|
||||
fromYaml = content: builtins.fromJSON (builtins.readFile
|
||||
(inputs.pkgs.runCommand "toJSON" {}
|
||||
|
||||
@@ -11,7 +11,6 @@ endif()
|
||||
|
||||
set(HPCSTAT_VERSION "unknown" CACHE STRING "Version of the hpcstat")
|
||||
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS headers filesystem)
|
||||
find_package(SqliteOrm REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
@@ -19,15 +18,17 @@ find_path(ZPP_BITS_INCLUDE_DIR zpp_bits.h REQUIRED)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_path(NAMEOF_INCLUDE_DIR nameof.hpp REQUIRED)
|
||||
find_package(date REQUIRED)
|
||||
find_package(OpenXLSX REQUIRED)
|
||||
find_package(httplib REQUIRED)
|
||||
find_package(termcolor REQUIRED)
|
||||
find_package(biu REQUIRED)
|
||||
|
||||
add_executable(hpcstat src/main.cpp src/env.cpp src/keys.cpp src/ssh.cpp src/sql.cpp src/lfs.cpp src/common.cpp
|
||||
src/push.cpp)
|
||||
target_compile_features(hpcstat PUBLIC cxx_std_23)
|
||||
src/push.cpp src/disk.cpp)
|
||||
target_compile_features(hpcstat PRIVATE cxx_std_23)
|
||||
target_include_directories(hpcstat PRIVATE ${PROJECT_SOURCE_DIR}/include ${ZPP_BITS_INCLUDE_DIR})
|
||||
target_link_libraries(hpcstat PRIVATE fmt::fmt Boost::headers Boost::filesystem sqlite_orm::sqlite_orm
|
||||
nlohmann_json::nlohmann_json range-v3::range-v3 date::date date::date-tz OpenXLSX::OpenXLSX httplib::httplib)
|
||||
target_link_libraries(hpcstat PRIVATE Boost::headers Boost::filesystem sqlite_orm::sqlite_orm
|
||||
nlohmann_json::nlohmann_json range-v3::range-v3 date::date date::date-tz httplib::httplib
|
||||
termcolor::termcolor biu::biu)
|
||||
target_compile_definitions(hpcstat PRIVATE HPCSTAT_VERSION="${HPCSTAT_VERSION}")
|
||||
|
||||
install(TARGETS hpcstat RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
{
|
||||
stdenv, cmake, pkg-config, standalone ? false, version ? null, makeWrapper, lib,
|
||||
boost, fmt, sqlite-orm, nlohmann_json, zpp-bits, range-v3, nameof, openssh, sqlite, date, openxlsx, httplib, openssl,
|
||||
boost, fmt, sqlite-orm, nlohmann_json, zpp-bits, range-v3, nameof, openssh, sqlite, date, httplib, openssl,
|
||||
termcolor, duc, biu
|
||||
}: stdenv.mkDerivation
|
||||
{
|
||||
name = "hpcstat";
|
||||
src = ./.;
|
||||
buildInputs =
|
||||
[ boost fmt sqlite-orm nlohmann_json zpp-bits range-v3 nameof sqlite date openxlsx httplib openssl.dev ];
|
||||
[ boost fmt sqlite-orm nlohmann_json zpp-bits range-v3 nameof sqlite date httplib termcolor openssl biu ];
|
||||
nativeBuildInputs = [ cmake pkg-config makeWrapper ];
|
||||
cmakeFlags = lib.optionals (version != null) [ "-DHPCSTAT_VERSION=${version}" ];
|
||||
postInstall =
|
||||
if standalone then "cp ${openssh}/bin/{ssh-add,ssh-keygen} $out/bin"
|
||||
if standalone then "cp ${openssh}/bin/{ssh-add,ssh-keygen} ${duc}/bin/duc $out/bin"
|
||||
else
|
||||
''
|
||||
wrapProgram $out/bin/hpcstat --set HPCSTAT_SHAREDIR $out/share/hpcstat \
|
||||
--set HPCSTAT_DATADIR /var/lib/hpcstat --set HPCSTAT_SSH_BINDIR ${openssh}/bin
|
||||
--set HPCSTAT_DATADIR /var/lib/hpcstat --set HPCSTAT_SSH_BINDIR ${openssh}/bin \
|
||||
--set HPCSTAT_DUC_BINDIR ${duc}/bin
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -11,19 +11,16 @@
|
||||
# include <thread>
|
||||
# include <chrono>
|
||||
# include <fstream>
|
||||
# include <fmt/format.h>
|
||||
# include <future>
|
||||
# include <date/date.h>
|
||||
# include <date/tz.h>
|
||||
# include <boost/interprocess/sync/file_lock.hpp>
|
||||
# include <zpp_bits.h>
|
||||
# include <biu.hpp>
|
||||
|
||||
namespace hpcstat
|
||||
{
|
||||
// run a program, wait until it exit, return its stdout if it return 0, otherwise nullopt
|
||||
std::optional<std::string> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin = std::nullopt,
|
||||
std::map<std::string, std::string> extra_env = {}
|
||||
);
|
||||
|
||||
using namespace biu::literals;
|
||||
// get current time
|
||||
long now();
|
||||
}
|
||||
|
||||
18
local/pkgs/hpcstat/include/hpcstat/disk.hpp
Normal file
18
local/pkgs/hpcstat/include/hpcstat/disk.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
# pragma once
|
||||
# include <hpcstat/common.hpp>
|
||||
|
||||
namespace hpcstat::disk
|
||||
{
|
||||
struct Usage
|
||||
{
|
||||
double Total;
|
||||
std::vector<std::pair<std::string, double>> Teacher; // 已排序
|
||||
std::vector<std::pair<std::string, double>> Student; // 已排序
|
||||
std::string Time;
|
||||
using serialize = zpp::bits::members<4>;
|
||||
};
|
||||
// 刷新 duc 数据库
|
||||
bool stat();
|
||||
// 从 duc 数据库中读取数据
|
||||
std::optional<Usage> get();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
# pragma once
|
||||
# include <hpcstat/common.hpp>
|
||||
# include <zpp_bits.h>
|
||||
# include <hpcstat/disk.hpp>
|
||||
|
||||
namespace hpcstat::sql
|
||||
{
|
||||
@@ -47,8 +47,11 @@ namespace hpcstat::sql
|
||||
std::string Status;
|
||||
bool operator==(const CheckJobData& other) const = default;
|
||||
};
|
||||
// 序列化任意数据,用于之后签名
|
||||
std::string serialize(auto data);
|
||||
struct DiskData
|
||||
{
|
||||
unsigned Id = 0;
|
||||
std::string Data;
|
||||
};
|
||||
// 初始化数据库
|
||||
bool initdb();
|
||||
// 将数据写入数据库
|
||||
@@ -59,8 +62,8 @@ namespace hpcstat::sql
|
||||
// 三个字符串分别是序列化后的数据,签名,指纹
|
||||
std::optional<std::vector<std::tuple<std::string, std::string, std::string>>>
|
||||
verify(std::string old_db, std::string new_db);
|
||||
// 将某个月份的数据导出到文件
|
||||
bool export_data(long start_time, long end_time, std::string filename);
|
||||
// 将某个月份的数据导出
|
||||
bool export_data(long start_time, long end_time);
|
||||
// 检查任务状态,返回有变化的任务 id、名称、现在的状态、提交时的 key、subaccount
|
||||
// 如果没有找到提交时的信息,则忽略这个任务
|
||||
std::optional<std::map<unsigned, std::tuple<std::string, std::string, std::string, std::optional<std::string>>>>
|
||||
|
||||
1
local/pkgs/hpcstat/share/keys/05
Normal file
1
local/pkgs/hpcstat/share/keys/05
Normal file
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9FmT0i2j9JsnyeVrEZP8gaWHnc5NnhJgb1sP8MP/pjx/GMEkms2LQvZYNw8MQvGA6HH/O2acy5NIdD69QkRlALXZlWpUQco8JDuJe7+2xkTMGPOAqB5YLMHRpFGHUmDMuSFGSg2YyLXaWXoWmib5xAvTL95xAcdNgp5xqWvO2N55edDeVOY5cTmIE2vC0nm5JSjMEMcIuqL8yJ3AweN4JkD8CVVy3po8f+krKsaYB+f21MqqSnCQ/cpKlWHuMN9k85hP/FB1E7gBXW/MuZ1uOm4IzjBhj8tYVN0UY7Mo2/9PhFqoBKGr6vs7Nx1mXBJ/A1lIKvW+ROvQ9ADpOfww6kPuHbX16gQ55JG7zneWeiP5pVaI4YZ4O1vAvARw/SaSFhRdpymPs5r+wdIDV9gGoqORrYqoPBz7Q02V71W+EV7WFAgxiJozO0vZwD9JJ2zivyIJfcVtIOMIvEhfsha7Hviut4JIOyoaEHjIZYsmvYHEeEBA4pTUHIUZlZj/St7U= 05@xmuhpc
|
||||
1
local/pkgs/hpcstat/share/keys/xly
Normal file
1
local/pkgs/hpcstat/share/keys/xly
Normal file
@@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCW2fx1Sim7X2i/e/RBPEl1q/XbV7wa9pmZfnRINHIv24MCUgtNZ5GHEEW7dvzrQBeRj3I7CAyK8fbuhv/l8HuDtjxJJ1fmcBp9UG5vfpb/UTxayJxHBRrwokp2JL7HKVviI6d8FcNa/T0CMoUNYXnel6dE3B78k9Q0dDxlOGS1MzgsP3Pn66lm0ww9FRAVHe+KkhFmwyQ1VHUxHgK4QjCIt7+9+PJE7fK0aVWBsR309pui7Pbm6mgd4d6mwiBeVvxsNGnI4DsO1hz4N2GapuQy19PDiG7A4H41Z5RYQnv/3XTy4TBXOFQm77v6pyGkCmG6BGnRdvMB6C0hWPJvudbsA/BNp4ApL7/CrwTdLp1z6ToAOLvKrUQAM+hcbJimnFVMXqz7iSYg99XTnzue7ncecp19XiaDJbM47bGXcT4nTO5XaiMYi2xGAHIrij5GIuFF5ymKYSp5ejb1VucMdKlaaAmS10+wdUcuT7tzX/IuVr5aqg2dsxT5aJCRhZ1k2V0= xly@xmuhpc
|
||||
@@ -1,35 +1,9 @@
|
||||
# include <hpcstat/common.hpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <hpcstat/sql.hpp>
|
||||
# include <hpcstat/disk.hpp>
|
||||
|
||||
namespace hpcstat
|
||||
{
|
||||
std::optional<std::string> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin,
|
||||
std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{
|
||||
namespace bp = boost::process;
|
||||
bp::ipstream output;
|
||||
bp::opstream input;
|
||||
std::unique_ptr<bp::child> process;
|
||||
bp::environment env = boost::this_process::environment();
|
||||
for (const auto& [key, value] : extra_env) env[key] = value;
|
||||
if (stdin)
|
||||
{
|
||||
process = std::make_unique<bp::child>
|
||||
(program.string(), bp::args(args), bp::std_out > output, bp::std_err > stderr, bp::std_in < input, env);
|
||||
input << *stdin;
|
||||
input.pipe().close();
|
||||
}
|
||||
else process = std::make_unique<bp::child>
|
||||
(program.string(), bp::args(args), bp::std_out > output, bp::std_err > stderr, bp::std_in < bp::null, env);
|
||||
process->wait();
|
||||
if (process->exit_code() != 0) return std::nullopt;
|
||||
std::stringstream ss;
|
||||
ss << output.rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
long now()
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::seconds>
|
||||
|
||||
129
local/pkgs/hpcstat/src/disk.cpp
Normal file
129
local/pkgs/hpcstat/src/disk.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
# include <hpcstat/disk.hpp>
|
||||
# include <hpcstat/env.hpp>
|
||||
|
||||
namespace hpcstat::disk
|
||||
{
|
||||
// 需要统计的目录,是否统计子目录
|
||||
std::map<std::string, bool> Directories =
|
||||
{
|
||||
{ "caiduanjun", true },
|
||||
{ "Gaona", true },
|
||||
{ "huangkai", true },
|
||||
{ "huangshengli", false },
|
||||
{ "kangjunyong", true },
|
||||
{ "lijing", true },
|
||||
{ "linwei", true },
|
||||
{ "Lixu", true },
|
||||
{ "wanghao", false },
|
||||
{ "wuyaping", true },
|
||||
{ "wuzhiming", true },
|
||||
{ "zhanhuahan", false }
|
||||
};
|
||||
|
||||
bool stat()
|
||||
{
|
||||
if (auto homedir = env::env("HOME"); !homedir)
|
||||
{ std::cerr << "HOME not set\n"; return false; }
|
||||
else if (auto ducbindir = env::env("HPCSTAT_DUC_BINDIR"); !ducbindir)
|
||||
{ std::cerr << "HPCSTAT_DUC_BINDIR not set\n"; return false; }
|
||||
else if (auto datadir = env::env("HPCSTAT_DATADIR"); !datadir)
|
||||
{ std::cerr << "HPCSTAT_DATADIR not set\n"; return false; }
|
||||
else if
|
||||
(
|
||||
auto result = biu::exec<{.DirectStdout = true, .DirectStderr = true}>
|
||||
(
|
||||
// duc index -d ./duc.db -p ~
|
||||
"{}/duc"_f(*ducbindir),
|
||||
{ "index", "-d", "{}/duc.db"_f(*datadir), "-p", *homedir }
|
||||
);
|
||||
!result
|
||||
)
|
||||
{ std::cerr << "failed to index\n"; return false; }
|
||||
else return true;
|
||||
}
|
||||
|
||||
std::optional<Usage> get()
|
||||
{
|
||||
if (auto homedir = env::env("HOME"); !homedir)
|
||||
{ std::cerr << "HOME not set\n"; return {}; }
|
||||
else if (auto ducbindir = env::env("HPCSTAT_DUC_BINDIR"); !ducbindir)
|
||||
{ std::cerr << "HPCSTAT_DUC_BINDIR not set\n"; return {}; }
|
||||
else if (auto datadir = env::env("HPCSTAT_DATADIR"); !datadir)
|
||||
{ std::cerr << "HPCSTAT_DATADIR not set\n"; return {}; }
|
||||
else
|
||||
{
|
||||
auto get_size = [&](std::optional<std::string> path) -> std::optional<double>
|
||||
{
|
||||
if
|
||||
(
|
||||
auto result = biu::exec
|
||||
(
|
||||
// duc ls -d ./duc.db -b -D /data/gpfs01/jykang/linwei/xxx
|
||||
"{}/duc"_f(*ducbindir),
|
||||
{
|
||||
"ls", "-d", "{}/duc.db"_f(*datadir), "-b", "-D",
|
||||
"{}{}{}"_f(*homedir, path ? "/" : "", path.value_or(""))
|
||||
}
|
||||
);
|
||||
!result
|
||||
)
|
||||
{ std::cerr << "failed to ls {}\n"_f(path); return {}; }
|
||||
else
|
||||
{
|
||||
std::smatch match;
|
||||
if (!std::regex_search(result.Stdout, match, std::regex(R"((\d+))")))
|
||||
{ std::cerr << "failed to parse {}\n"_f(result.Stdout); return std::nullopt; }
|
||||
return std::stod(match[1]) / 1024 / 1024 / 1024;
|
||||
}
|
||||
};
|
||||
auto get_subdir = [&](std::string path) -> std::vector<std::string>
|
||||
{
|
||||
std::filesystem::directory_iterator it(*homedir + "/" + path);
|
||||
std::vector<std::string> result;
|
||||
for (const auto& entry : it)
|
||||
if (entry.is_directory()) result.push_back(entry.path().filename().string());
|
||||
return result;
|
||||
};
|
||||
auto get_date = [&]() -> std::optional<std::string>
|
||||
{
|
||||
if
|
||||
(
|
||||
// duc info -d ./duc.db
|
||||
auto result = biu::exec
|
||||
("{}/duc"_f(*ducbindir), { "info", "-d", "{}/duc.db"_f(*datadir) });
|
||||
!result
|
||||
)
|
||||
{ std::cerr << "failed to get duc info\n"; return {}; }
|
||||
else
|
||||
{
|
||||
std::smatch match;
|
||||
// search string like 2024-06-08 13:45:19
|
||||
if (!std::regex_search(result.Stdout, match, R"((\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}))"_re))
|
||||
{ std::cerr << "failed to parse {}\n"_f(result.Stdout); return {}; }
|
||||
return match[1];
|
||||
}
|
||||
};
|
||||
Usage usage;
|
||||
if (auto size = get_size({})) usage.Total = *size; else return {};
|
||||
if (auto date = get_date()) usage.Time = *date; else return {};
|
||||
for (const auto& [dir, recursive] : Directories)
|
||||
{
|
||||
if (!std::filesystem::exists(*homedir + "/" + dir))
|
||||
{ std::cerr << "{} does not exist\n"_f(*homedir + "/" + dir); continue; }
|
||||
if (auto size = get_size(dir)) usage.Teacher.push_back({ dir, *size });
|
||||
else return {};
|
||||
if (recursive) for (const auto& subdir : get_subdir(dir))
|
||||
{
|
||||
if (auto size = get_size(dir + "/" + subdir); size)
|
||||
usage.Student.push_back({ dir + "/" + subdir, *size });
|
||||
else return {};
|
||||
}
|
||||
}
|
||||
std::sort(usage.Teacher.begin(), usage.Teacher.end(),
|
||||
[](const auto& a, const auto& b) { return a.second > b.second; });
|
||||
std::sort(usage.Student.begin(), usage.Student.end(),
|
||||
[](const auto& a, const auto& b) { return a.second > b.second; });
|
||||
return usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace hpcstat::env
|
||||
{
|
||||
if (auto value = std::getenv(name.c_str()); !value)
|
||||
{
|
||||
if (required) std::cerr << fmt::format("Failed to get environment variable {}\n", name);
|
||||
if (required) std::cerr << "Failed to get environment variable {}\n"_f(name);
|
||||
return std::nullopt;
|
||||
}
|
||||
else return value;
|
||||
|
||||
@@ -9,11 +9,13 @@ namespace hpcstat
|
||||
{ "umC3/RB1vS8TQBHsY3IzhOiyqVrOSw2fB3rIpDQSmf4", { "xll", "Leilei Xiang" } },
|
||||
{ "fdq5k13N2DAzIK/2a1Mm4/ZVsDUgT623TSOXsVswxT8", { "yjq", "Junqi Yao" } },
|
||||
{ "8USxEYi8ePPpLhk5FYBo2udT7/NFmEe8c2+oQajGXzA", { "zem", "Enming Zhang" } },
|
||||
{ "C52EURGhRHtf+odfmE2qofh7NO24MnGB3Q8GhRQhHiM", { "xly", "Linyang Xie" } },
|
||||
{ "7bmG24muNsaAZkCy7mQ9Nf2HuNafmvUO+Hf1bId9zts", { "00", "Yaping Wu" } },
|
||||
{ "dtx0QxdgFrXn2SYxtIRz43jIAH6rLgJidSdTvuTuews", { "01", "Jing Li" } },
|
||||
{ "8crUO9u4JiVqw3COyjXfzZe87s6XZFhvi0LaY0Mv6bg", { "02", "Huahan Zhan" } },
|
||||
{ "QkmIYw7rmDEAP+LDWxm6L2/XLnAqTwRUB7B0pxYlOUs", { "03", "Na Gao" } },
|
||||
{ "WfUP4s0BzEspDweDIrOIed4MbW4v9W1spbp0EN6O5dk", { "04", "Duanjun Cai" } },
|
||||
{ "VmVTvYnOOXOFcw+RH2AuUcj7hioieIJhwGOCDCfm0/w", { "05", "Xu Li" } },
|
||||
{ "6NmbGMvtcNlsmN61ZtiV1cg0aOGeM8sCa4rk2brsS4k", { "hpcstat", "hpcstat" } }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# include <hpcstat/lfs.hpp>
|
||||
# include <hpcstat/env.hpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <nlohmann/json.hpp>
|
||||
|
||||
namespace hpcstat::lfs
|
||||
@@ -18,7 +17,7 @@ namespace hpcstat::lfs
|
||||
{
|
||||
if (!valid_args.contains(it->substr(1)))
|
||||
{
|
||||
std::cerr << fmt::format("Unknown bsub argument: {}\n", *it)
|
||||
std::cerr << "Unknown bsub argument: {}\n"_f(*it)
|
||||
<< "bsub might support this argument, but hpcstat currently does not support it.\n"
|
||||
"If you are sure this argument is supported by bsub,\n"
|
||||
"please submit issue on [github](https://github.com/CHN-beta/hpcstat) or contact chn@chn.moe.\n";
|
||||
@@ -28,19 +27,15 @@ namespace hpcstat::lfs
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (auto result = exec(*bsub, args); !result) return std::nullopt;
|
||||
if (auto result = biu::exec(*bsub, args); !result) return std::nullopt;
|
||||
else
|
||||
{
|
||||
// Job <462270> is submitted to queue <normal_1day>.
|
||||
std::regex re(R"r(Job <(\d+)> is submitted to queue <(\w+)>.)r");
|
||||
std::smatch match;
|
||||
if (std::regex_search(*result, match, re))
|
||||
if (std::regex_search(result.Stdout, match, re))
|
||||
return std::make_pair(std::stoi(match[1]), match[2]);
|
||||
else
|
||||
{
|
||||
std::cerr << fmt::format("Failed to parse job id from output: {}\n", *result);
|
||||
return std::nullopt;
|
||||
}
|
||||
else { std::cerr << "Failed to parse job id from output: {}\n"_f(result.Stdout); return std::nullopt; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,11 +44,10 @@ namespace hpcstat::lfs
|
||||
{
|
||||
if
|
||||
(
|
||||
auto result = exec
|
||||
auto result = biu::exec<{.SearchPath = true}>
|
||||
(
|
||||
boost::process::search_path("bjobs").string(),
|
||||
{ "-a", "-o", "jobid submit_time stat cpu_used job_name", "-json" },
|
||||
std::nullopt, { { "LSB_DISPLAY_YEAR", "Y" } }
|
||||
"bjobs", { "-a", "-o", "jobid submit_time stat cpu_used job_name", "-json" },
|
||||
{}, { { "LSB_DISPLAY_YEAR", "Y" } }
|
||||
);
|
||||
!result
|
||||
)
|
||||
@@ -61,12 +55,9 @@ namespace hpcstat::lfs
|
||||
else
|
||||
{
|
||||
nlohmann::json j;
|
||||
try { j = nlohmann::json::parse(*result); }
|
||||
try { j = nlohmann::json::parse(result.Stdout); }
|
||||
catch (nlohmann::json::parse_error& e)
|
||||
{
|
||||
std::cerr << fmt::format("Failed to parse bjobs output: {}\n", e.what());
|
||||
return std::nullopt;
|
||||
}
|
||||
{ std::cerr << "Failed to parse bjobs output: {}\n"_f(e.what()); return std::nullopt; }
|
||||
std::map<unsigned, std::tuple<std::string, std::string, double, std::string>> jobs;
|
||||
for (auto& job : j["RECORDS"])
|
||||
{
|
||||
@@ -78,7 +69,7 @@ namespace hpcstat::lfs
|
||||
{
|
||||
try { cpu_used = std::stof(cpu_used_str.substr(0, cpu_used_str.find(' '))); }
|
||||
catch (std::invalid_argument& e)
|
||||
{ std::cerr << fmt::format("Failed to parse cpu used: {}\n", e.what()); return std::nullopt; }
|
||||
{ std::cerr << "Failed to parse cpu used: {}\n"_f(e.what()); return std::nullopt; }
|
||||
}
|
||||
jobs[std::stoi(job["JOBID"].get<std::string>())] =
|
||||
{ job["SUBMIT_TIME"], status, cpu_used, job["JOB_NAME"] };
|
||||
@@ -88,16 +79,8 @@ namespace hpcstat::lfs
|
||||
}
|
||||
std::optional<std::string> bjobs_detail(unsigned jobid)
|
||||
{
|
||||
if
|
||||
(
|
||||
auto result = exec
|
||||
(
|
||||
boost::process::search_path("bjobs").string(),
|
||||
{ "-l", std::to_string(jobid) }
|
||||
);
|
||||
!result
|
||||
)
|
||||
if (auto result = biu::exec<{.SearchPath = true}>("bjobs", { "-l", "{}"_f(jobid) }); !result)
|
||||
return std::nullopt;
|
||||
else return *result;
|
||||
else return result.Stdout;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
# include <hpcstat/keys.hpp>
|
||||
# include <hpcstat/lfs.hpp>
|
||||
# include <hpcstat/push.hpp>
|
||||
# include <hpcstat/disk.hpp>
|
||||
# include <range/v3/view.hpp>
|
||||
# include <boost/exception/diagnostic_information.hpp>
|
||||
# include <boost/interprocess/sync/file_lock.hpp>
|
||||
# include <boost/filesystem.hpp>
|
||||
# include <termcolor/termcolor.hpp>
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
@@ -22,7 +23,10 @@ int main(int argc, const char** argv)
|
||||
std::vector<std::string> args(argv, argv + argc);
|
||||
|
||||
if (args.size() == 1)
|
||||
{ std::cout << "Usage: hpcstat initdb|login|logout|submitjob|finishjob|verify|export|version\n"; return 1; }
|
||||
{
|
||||
std::cout << "Usage: hpcstat initdb|login|logout|submitjob|finishjob|verify|export|version|diskstat\n";
|
||||
return 1;
|
||||
}
|
||||
else if (args[1] == "initdb")
|
||||
{
|
||||
lock.lock();
|
||||
@@ -43,16 +47,41 @@ int main(int argc, const char** argv)
|
||||
.Time = now(), .Key = *fp, .SessionId = *session, .Subaccount = env::env("HPCSTAT_SUBACCOUNT"),
|
||||
.Ip = env::env("SSH_CONNECTION"), .Interactive = env::interactive()
|
||||
};
|
||||
auto signature = ssh::sign(sql::serialize(data), *fp);
|
||||
auto signature = ssh::sign(biu::serialize<char>(data), *fp);
|
||||
if (!signature) return 1;
|
||||
data.Signature = *signature;
|
||||
lock.lock();
|
||||
sql::writedb(data);
|
||||
if (env::interactive()) std::cout << fmt::format
|
||||
(
|
||||
"\33[2K\rLogged in as {} (Fingerprint: SHA256:{}{}).\n", Keys[*fp].Username, *fp,
|
||||
sub_account ? fmt::format(" Subaccount {}", *sub_account) : ""
|
||||
);
|
||||
if (env::interactive())
|
||||
{
|
||||
std::cout << "\33[2K\rLogged in as {} (Fingerprint: SHA256:{}{}).\n"_f
|
||||
(Keys[*fp].Username, *fp, sub_account ? " Subaccount {}"_f(*sub_account) : "");
|
||||
if (auto disk_stat = disk::get(); !disk_stat)
|
||||
std::cerr << "Failed to get disk usage statistic.\n";
|
||||
else
|
||||
{
|
||||
double percent = disk_stat->Total / 800 * 100;
|
||||
auto color = percent > 95 ? termcolor::red<char> :
|
||||
percent > 80 ? termcolor::yellow<char> : termcolor::green<char>;
|
||||
auto bgcolor = percent > 95 ? termcolor::on_red<char> :
|
||||
percent > 80 ? termcolor::on_yellow<char> : termcolor::on_green<char>;
|
||||
std::cout
|
||||
<< color << "disk usage: " << termcolor::reset
|
||||
<< bgcolor << termcolor::white
|
||||
<< "{:.1f}% ({:.1f}GB / ~800GB)"_f(percent, disk_stat->Total) << termcolor::reset
|
||||
<< color << " (estimated, counted at {})\n"_f(disk_stat->Time) << termcolor::reset;
|
||||
if (percent > 80)
|
||||
{
|
||||
std::cout << color << "Top 3 directories owned by teacher:\n";
|
||||
for (auto& [name, size] : disk_stat->Teacher | ranges::views::take(3))
|
||||
std::cout << " {:.1f}GB {}\n"_f(size, name);
|
||||
std::cout << color << "Top 3 directories owned by student:\n";
|
||||
for (auto& [name, size] : disk_stat->Student | ranges::views::take(3))
|
||||
std::cout << " {:.1f}GB {}\n"_f(size, name);
|
||||
std::cout << termcolor::reset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args[1] == "logout")
|
||||
@@ -79,13 +108,12 @@ int main(int argc, const char** argv)
|
||||
.JobCommand = args | ranges::views::drop(2) | ranges::views::join(' ') | ranges::to<std::string>(),
|
||||
.Subaccount = env::env("HPCSTAT_SUBACCOUNT"), .Ip = env::env("SSH_CONNECTION")
|
||||
};
|
||||
auto signature = ssh::sign(sql::serialize(data), *fp);
|
||||
auto signature = ssh::sign(biu::serialize<char>(data), *fp);
|
||||
if (!signature) return 1;
|
||||
data.Signature = *signature;
|
||||
lock.lock();
|
||||
sql::writedb(data);
|
||||
std::cout << fmt::format
|
||||
("Job <{}> was submitted to <{}> by <{}>.\n", bsub->first, bsub->second, Keys[*fp].Username);
|
||||
std::cout << "Job <{}> was submitted to <{}> by <{}>.\n"_f(bsub->first, bsub->second, Keys[*fp].Username);
|
||||
}
|
||||
}
|
||||
else if (args[1] == "finishjob")
|
||||
@@ -117,12 +145,7 @@ int main(int argc, const char** argv)
|
||||
.SubmitTime = std::get<0>(all_jobs->at(jobid)), .JobDetail = *detail, .Key = *fp,
|
||||
.CpuTime = std::get<2>(all_jobs->at(jobid)),
|
||||
};
|
||||
if
|
||||
(
|
||||
auto signature = ssh::sign(sql::serialize(data), *fp);
|
||||
!signature
|
||||
)
|
||||
return 1;
|
||||
if (auto signature = ssh::sign(biu::serialize<char>(data), *fp); !signature) return 1;
|
||||
else { data.Signature = *signature; sql::writedb(data); }
|
||||
}
|
||||
}
|
||||
@@ -133,7 +156,7 @@ int main(int argc, const char** argv)
|
||||
if (auto db_verify_result = sql::verify(args[2], args[3]); !db_verify_result) return 1;
|
||||
else for (auto& data : *db_verify_result)
|
||||
if (!std::apply(ssh::verify, data))
|
||||
{ std::cerr << fmt::format("Failed to verify data: {}\n", std::get<0>(data)); return 1; }
|
||||
{ std::cerr << "Failed to verify data: {}\n"_f(std::get<0>(data)); return 1; }
|
||||
}
|
||||
else if (args[1] == "export")
|
||||
{
|
||||
@@ -144,11 +167,7 @@ int main(int argc, const char** argv)
|
||||
auto end = sys_seconds(sys_days(month(month_n) / 1 / year_n + months(1)))
|
||||
.time_since_epoch().count();
|
||||
lock.lock();
|
||||
if
|
||||
(
|
||||
!sql::export_data
|
||||
(begin, end, fmt::format("hpcstat-{}-{}.xlsx", year_n, month_n))
|
||||
)
|
||||
if (!sql::export_data(begin, end))
|
||||
return 1;
|
||||
}
|
||||
else if (args[1] == "push")
|
||||
@@ -158,6 +177,8 @@ int main(int argc, const char** argv)
|
||||
else if (!push::push(*jobs)) return 1;
|
||||
}
|
||||
else if (args[1] == "version") { std::cout << HPCSTAT_VERSION << std::endl; }
|
||||
else if (args[1] == "diskstat")
|
||||
{ if (!disk::stat()) { std::cerr << "Failed to collect disk usage statistic.\n"; return 1; } }
|
||||
else { std::cerr << "Unknown command.\n"; return 1; }
|
||||
}
|
||||
catch (...) { std::cerr << boost::current_exception_diagnostic_information() << std::endl; return 1; }
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace hpcstat::push
|
||||
// 读取配置
|
||||
if (auto datadir = env::env("HPCSTAT_DATADIR"); !datadir) return false;
|
||||
else if (std::ifstream config_file(std::filesystem::path(*datadir) / "push.json"); !config_file)
|
||||
{ fmt::print("Push failed: failed to open push.json\n"); return false; }
|
||||
{ std::cout << "Push failed: failed to open push.json\n"; return false; }
|
||||
else
|
||||
{
|
||||
auto config_string = std::string(std::istreambuf_iterator<char>(config_file), {});
|
||||
@@ -29,20 +29,18 @@ namespace hpcstat::push
|
||||
user_string += "::" + *std::get<3>(info);
|
||||
if (users.contains(user_string))
|
||||
{
|
||||
auto path = fmt::format
|
||||
auto path = "/api/send/message/?appToken={}&content={}&uid={}"_f
|
||||
(
|
||||
"/api/send/message/?appToken={}&content={}&uid={}",
|
||||
token,
|
||||
boost::urls::encode
|
||||
(
|
||||
fmt::format("{} {} {}", std::get<1>(info), std::get<0>(info), id),
|
||||
"{} {} {}"_f(std::get<1>(info), std::get<0>(info), id),
|
||||
boost::urls::unreserved_chars
|
||||
),
|
||||
users[user_string]
|
||||
);
|
||||
auto res = cli.Get(path.c_str());
|
||||
if (res.error() != httplib::Error::Success)
|
||||
{ fmt::print("Push failed: {}\n", nameof::nameof_enum(res.error())); return false; }
|
||||
if (res.error() != httplib::Error::Success) { std::cout << "Push failed: {}\n"_f(res.error()); return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +50,7 @@ namespace hpcstat::push
|
||||
| ranges::views::filter([](const auto& pair)
|
||||
{ return std::get<2>(pair.second) == "LNoYfq/SM7l8sFAy325WpC+li+kZl3jwST7TmP72Tz8"; })
|
||||
| ranges::views::transform([](const auto& pair)
|
||||
{ return fmt::format("{} {} {}", std::get<1>(pair.second), std::get<0>(pair.second), pair.first); })
|
||||
{ return "{} {} {}"_f(std::get<1>(pair.second), std::get<0>(pair.second), pair.first); })
|
||||
| ranges::views::chunk(20)
|
||||
| ranges::views::transform([](auto chunk) { return chunk | ranges::views::join('\n'); })
|
||||
| ranges::to<std::vector<std::string>>;
|
||||
@@ -62,13 +60,13 @@ namespace hpcstat::push
|
||||
cli.enable_server_certificate_verification(false);
|
||||
for (auto& message : messages)
|
||||
{
|
||||
auto path = fmt::format
|
||||
("/notify.php?message={}", boost::urls::encode(message, boost::urls::unreserved_chars));
|
||||
auto path = "/notify.php?message={}"_f
|
||||
(boost::urls::encode(message, boost::urls::unreserved_chars));
|
||||
auto res = cli.Get(path.c_str());
|
||||
if (res.error() != httplib::Error::Success)
|
||||
{ fmt::print("Push failed: {}\n", nameof::nameof_enum(res.error())); return false; }
|
||||
{ std::cout << "Push failed: {}\n"_f(res.error()); return false; }
|
||||
else if (res->status != 200)
|
||||
{ fmt::print("Push failed: status code {}\n", res->status); return false; }
|
||||
{ std::cout << "Push failed: status code {}\n"_f(res->status); return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,20 +7,9 @@
|
||||
# include <nameof.hpp>
|
||||
# define SQLITE_ORM_OPTIONAL_SUPPORTED
|
||||
# include <sqlite_orm/sqlite_orm.h>
|
||||
# include <OpenXLSX.hpp>
|
||||
|
||||
namespace hpcstat::sql
|
||||
{
|
||||
std::string serialize(auto data)
|
||||
{
|
||||
auto [serialized_data_byte, out] = zpp::bits::data_out();
|
||||
out(data).or_throw();
|
||||
static_assert(sizeof(char) == sizeof(std::byte));
|
||||
return { reinterpret_cast<char*>(serialized_data_byte.data()), serialized_data_byte.size() };
|
||||
}
|
||||
template std::string serialize(LoginData);
|
||||
template std::string serialize(SubmitJobData);
|
||||
template std::string serialize(FinishJobData);
|
||||
auto connect(std::optional<std::string> dbfile = std::nullopt)
|
||||
{
|
||||
auto conn = [&]() { return std::make_optional(sqlite_orm::make_storage
|
||||
@@ -132,15 +121,11 @@ namespace hpcstat::sql
|
||||
for (; old_data_it != old_query.end() && new_data_it != new_query.end(); ++old_data_it, ++new_data_it)
|
||||
if (*old_data_it != *new_data_it)
|
||||
{
|
||||
std::cerr << fmt::format
|
||||
("Data mismatch: {} {} != {}.\n", nameof::nameof_type<T>(), old_data_it->Id, new_data_it->Id);
|
||||
return std::nullopt;
|
||||
std::cerr << "Data mismatch: {} {} != {}.\n"_f(nameof::nameof_type<T>(), old_data_it->Id, new_data_it->Id);
|
||||
return {};
|
||||
}
|
||||
if (old_data_it != old_query.end() && new_data_it == new_query.end())
|
||||
{
|
||||
std::cerr << fmt::format("Data mismatch in {}.\n", nameof::nameof_type<T>());
|
||||
return std::nullopt;
|
||||
}
|
||||
{ std::cerr << "Data mismatch in {}.\n"_f(nameof::nameof_type<T>()); return {}; }
|
||||
else if constexpr (requires(T data) { data.Signature; })
|
||||
{
|
||||
std::vector<std::tuple<std::string, std::string, std::string>> diff;
|
||||
@@ -149,7 +134,7 @@ namespace hpcstat::sql
|
||||
auto data = *old_data_it;
|
||||
data.Signature = "";
|
||||
data.Id = 0;
|
||||
diff.push_back({ serialize(data), old_data_it->Signature, old_data_it->Key });
|
||||
diff.push_back({ biu::serialize<char>(data), old_data_it->Signature, old_data_it->Key });
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
@@ -192,35 +177,35 @@ namespace hpcstat::sql
|
||||
if (auto diff = job_submit.Time - submit_date; std::abs(diff) < 3600)
|
||||
{
|
||||
result = job_submit;
|
||||
if (std::abs(diff) > 60)
|
||||
std::cerr << fmt::format("large difference found: {} {}\n", job_id, diff);
|
||||
if (std::abs(diff) > 60) std::cerr << "large difference found: {} {}\n"_f(job_id, diff);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
bool export_data(long start_time, long end_time, std::string filename)
|
||||
bool export_data(long start_time, long end_time)
|
||||
{
|
||||
if (auto conn = connect(); !conn) return false;
|
||||
else
|
||||
{
|
||||
struct StatResult
|
||||
// 对于一个账户的总计
|
||||
struct StatAccount
|
||||
{
|
||||
double CpuTime = 0;
|
||||
unsigned LoginInteractive = 0, LoginNonInteractive = 0, SubmitJob = 0, FinishJobSuccess = 0,
|
||||
FinishJobFailed = 0;
|
||||
StatResult& operator+=(const StatResult& rhs)
|
||||
{
|
||||
CpuTime += rhs.CpuTime;
|
||||
LoginInteractive += rhs.LoginInteractive;
|
||||
LoginNonInteractive += rhs.LoginNonInteractive;
|
||||
SubmitJob += rhs.SubmitJob;
|
||||
FinishJobSuccess += rhs.FinishJobSuccess;
|
||||
FinishJobFailed += rhs.FinishJobFailed;
|
||||
return *this;
|
||||
}
|
||||
unsigned LoginInteractive = 0, LoginNonInteractive = 0, FinishJobSuccess = 0, FinishJobFailed = 0;
|
||||
};
|
||||
// Key SubAccount -> StatResult
|
||||
std::map<std::pair<std::string, std::optional<std::string>>, StatResult> stat;
|
||||
// Key SubAccount -> StatAccount
|
||||
std::map<std::pair<std::string, std::string>, StatAccount> stat_subaccount;
|
||||
// Key -> StatAccount
|
||||
std::map<std::optional<std::string>, StatAccount> stat_account;
|
||||
// 每一个任务
|
||||
struct StatJob
|
||||
{
|
||||
unsigned JobId;
|
||||
std::optional<std::string> Key, SessionId, SubmitDir, JobCommand, Ip;
|
||||
std::string JobResult, SubmitTime;
|
||||
double CpuTime;
|
||||
};
|
||||
std::vector<StatJob> stat_job;
|
||||
// CpuTime & FinishJobSuccess & FinishJobFailed
|
||||
for
|
||||
(
|
||||
@@ -228,14 +213,36 @@ namespace hpcstat::sql
|
||||
(sqlite_orm::between(&FinishJobData::Time, start_time, end_time)))
|
||||
)
|
||||
{
|
||||
auto job_in_submit = search_job_in_submit
|
||||
(conn, it.JobId, it.SubmitTime);
|
||||
std::pair<std::string, std::optional<std::string>> key;
|
||||
if (!job_in_submit) key = { "", {} };
|
||||
else key = std::make_pair(job_in_submit->Key, job_in_submit->Subaccount);
|
||||
stat[key].CpuTime += it.CpuTime / 3600;
|
||||
if (it.JobResult == "DONE") stat[key].FinishJobSuccess++;
|
||||
else stat[key].FinishJobFailed++;
|
||||
stat_job.push_back
|
||||
({ .JobId = it.JobId, .JobResult = it.JobResult, .SubmitTime = it.SubmitTime, .CpuTime = it.CpuTime });
|
||||
if (auto job_in_submit = search_job_in_submit
|
||||
(conn, it.JobId, it.SubmitTime))
|
||||
{
|
||||
{
|
||||
auto& _ = stat_job.back();
|
||||
_.Key = job_in_submit->Key;
|
||||
_.SessionId = job_in_submit->SessionId;
|
||||
_.SubmitDir = job_in_submit->SubmitDir;
|
||||
_.JobCommand = job_in_submit->JobCommand;
|
||||
_.Ip = job_in_submit->Ip;
|
||||
}
|
||||
stat_account[job_in_submit->Key].CpuTime += it.CpuTime / 3600;
|
||||
if (it.JobResult == "DONE") stat_account[job_in_submit->Key].FinishJobSuccess++;
|
||||
else stat_account[job_in_submit->Key].FinishJobFailed++;
|
||||
if (job_in_submit->Subaccount)
|
||||
{
|
||||
stat_subaccount[{job_in_submit->Key, *job_in_submit->Subaccount}].CpuTime += it.CpuTime / 3600;
|
||||
if (it.JobResult == "DONE")
|
||||
stat_subaccount[{job_in_submit->Key, *job_in_submit->Subaccount}].FinishJobSuccess++;
|
||||
else stat_subaccount[{job_in_submit->Key, *job_in_submit->Subaccount}].FinishJobFailed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
stat_account[std::nullopt].CpuTime += it.CpuTime / 3600;
|
||||
if (it.JobResult == "DONE") stat_account[std::nullopt].FinishJobSuccess++;
|
||||
else stat_account[std::nullopt].FinishJobFailed++;
|
||||
}
|
||||
}
|
||||
// LoginInteractive & LoginNonInteractive
|
||||
for
|
||||
@@ -244,64 +251,45 @@ namespace hpcstat::sql
|
||||
(sqlite_orm::between(&LoginData::Time, start_time, end_time)))
|
||||
)
|
||||
{
|
||||
auto key = std::make_pair(it.Key, it.Subaccount);
|
||||
if (it.Interactive) stat[key].LoginInteractive++; else stat[key].LoginNonInteractive++;
|
||||
if (Keys[it.Key].Username == "hpcstat") continue;
|
||||
if (it.Interactive) stat_account[it.Key].LoginInteractive++; else stat_account[it.Key].LoginNonInteractive++;
|
||||
if (it.Subaccount)
|
||||
{
|
||||
if (it.Interactive) stat_subaccount[{it.Key, *it.Subaccount}].LoginInteractive++;
|
||||
else stat_subaccount[{it.Key, *it.Subaccount}].LoginNonInteractive++;
|
||||
}
|
||||
}
|
||||
// SubmitJob
|
||||
for
|
||||
(
|
||||
auto& it : conn->get_all<SubmitJobData>(sqlite_orm::where
|
||||
(sqlite_orm::between(&SubmitJobData::Time, start_time, end_time)))
|
||||
)
|
||||
stat[{it.Key,it.Subaccount }].SubmitJob++;
|
||||
// add all result with subaccount into result without subaccount
|
||||
std::map<std::string, StatResult> stat_without_subaccount;
|
||||
for (auto& [key, value] : stat) stat_without_subaccount[key.first] += value;
|
||||
// remove all result without subaccount
|
||||
std::erase_if(stat, [](auto& it) { return !it.first.second; });
|
||||
// write to excel
|
||||
OpenXLSX::XLDocument doc;
|
||||
doc.create(filename);
|
||||
doc.workbook().addWorksheet("Statistics");
|
||||
auto wks1 = doc.workbook().worksheet("Statistics");
|
||||
wks1.row(1).values() = std::vector<std::string>
|
||||
// export to markdown
|
||||
std::cout << "| 账号 | 使用核时 | 登陆次数(交互式) | 登陆次数(非交互式) | 成功任务数 | 失败任务数 | SSH密钥编号::指纹 |\n";
|
||||
std::cout << "| :--: | :--: | :--: | :--: | :--: | :--: | :--: |\n";
|
||||
std::vector<std::pair<std::optional<std::string>, StatAccount>> stat_account_vector
|
||||
(stat_account.begin(), stat_account.end());
|
||||
auto compare = [](auto& a, auto& b)
|
||||
{
|
||||
"Username", "FingerPrint", "CpuTime", "LoginInteractive", "LoginNonInteractive",
|
||||
"SubmitJob", "FinishJobSuccess", "FinishJobFailed"
|
||||
if (a.first)
|
||||
{ if (b.first) return Keys[*a.first].PubkeyFilename < Keys[*b.first].PubkeyFilename; else return true; }
|
||||
else return false;
|
||||
};
|
||||
for
|
||||
(
|
||||
auto [row, it] = std::tuple(2, stat_without_subaccount.begin());
|
||||
it != stat_without_subaccount.end();
|
||||
it++, row++
|
||||
)
|
||||
wks1.row(row).values() = std::vector<std::string>
|
||||
{
|
||||
Keys.contains(it->first) ? Keys[it->first].Username : "(unknown)",
|
||||
it->first, fmt::format("{:.2f}", it->second.CpuTime),
|
||||
std::to_string(it->second.LoginInteractive), std::to_string(it->second.LoginNonInteractive),
|
||||
std::to_string(it->second.SubmitJob), std::to_string(it->second.FinishJobSuccess),
|
||||
std::to_string(it->second.FinishJobFailed)
|
||||
};
|
||||
doc.workbook().addWorksheet("StatisticsWithSubAccount");
|
||||
auto wks2 = doc.workbook().worksheet("StatisticsWithSubAccount");
|
||||
wks2.row(1).values() = std::vector<std::string>
|
||||
{
|
||||
"Username::SubAccount", "CpuTime", "LoginInteractive", "LoginNonInteractive",
|
||||
"SubmitJob", "FinishJobSuccess", "FinishJobFailed"
|
||||
};
|
||||
for (auto [row, it] = std::tuple(2, stat.begin()); it != stat.end(); it++, row++)
|
||||
wks2.row(row).values() = std::vector<std::string>
|
||||
{
|
||||
(Keys.contains(it->first.first) ? Keys[it->first.first].Username : "(unknown)")
|
||||
+ "::" + *it->first.second,
|
||||
fmt::format("{:.2f}", it->second.CpuTime),
|
||||
std::to_string(it->second.LoginInteractive), std::to_string(it->second.LoginNonInteractive),
|
||||
std::to_string(it->second.SubmitJob), std::to_string(it->second.FinishJobSuccess),
|
||||
std::to_string(it->second.FinishJobFailed)
|
||||
};
|
||||
doc.workbook().deleteSheet("Sheet1");
|
||||
doc.save();
|
||||
std::sort(stat_account_vector.begin(), stat_account_vector.end(), compare);
|
||||
for (auto& [key, stat] : stat_account_vector)
|
||||
std::cout << "| {} | {:.2f} | {} | {} | {} | {} | `{}::{}` |\n"_f
|
||||
(
|
||||
key ? Keys[*key].Username : "(unknown)", stat.CpuTime, stat.LoginInteractive, stat.LoginNonInteractive,
|
||||
stat.FinishJobSuccess, stat.FinishJobFailed, key ? Keys[*key].PubkeyFilename : "", key
|
||||
);
|
||||
for (auto& [key_subaccount, stat] : stat_subaccount)
|
||||
std::cout << "| {}::{} | {:.2f} | {} | {} | {} | {} | `{}::{}` |\n"_f
|
||||
(
|
||||
Keys[key_subaccount.first].Username, key_subaccount.second, stat.CpuTime,
|
||||
stat.LoginInteractive, stat.LoginNonInteractive, stat.FinishJobSuccess, stat.FinishJobFailed,
|
||||
Keys[key_subaccount.first].PubkeyFilename, key_subaccount.first
|
||||
);
|
||||
std::cout << "\n";
|
||||
std::cout << "| 任务ID | 任务结果 | 提交时间 | 使用核时 | SSH指纹 | 会话ID | 提交目录 | 任务命令 | TCP连接 |\n";
|
||||
std::cout << "| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |\n";
|
||||
for (auto& it : stat_job)
|
||||
std::cout << "| {} | {} | {} | {:.2f} | `{}` | `{}` | `{}` | `{}` | `{}` |\n"_f
|
||||
(it.JobId, it.JobResult, it.SubmitTime, it.CpuTime, it.Key, it.SessionId, it.SubmitDir, it.JobCommand, it.Ip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# include <hpcstat/keys.hpp>
|
||||
# include <hpcstat/env.hpp>
|
||||
# include <boost/filesystem.hpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <boost/dll.hpp>
|
||||
|
||||
namespace hpcstat::ssh
|
||||
@@ -13,8 +12,7 @@ namespace hpcstat::ssh
|
||||
return std::nullopt;
|
||||
else if
|
||||
(
|
||||
auto output =
|
||||
exec(std::filesystem::path(*sshbindir) / "ssh-add", { "-l" });
|
||||
auto output = biu::exec(std::filesystem::path(*sshbindir) / "ssh-add", { "-l" });
|
||||
!output
|
||||
)
|
||||
{ std::cerr << "Failed to get ssh fingerprints\n"; return std::nullopt; }
|
||||
@@ -24,11 +22,13 @@ namespace hpcstat::ssh
|
||||
std::smatch match;
|
||||
for
|
||||
(
|
||||
auto i = std::sregex_iterator(output->begin(), output->end(), pattern);
|
||||
i != std::sregex_iterator(); ++i
|
||||
auto i = std::sregex_iterator
|
||||
(output.Stdout.begin(), output.Stdout.end(), pattern);
|
||||
i != std::sregex_iterator();
|
||||
++i
|
||||
)
|
||||
if (Keys.contains(i->str(1))) return i->str(1);
|
||||
std::cerr << fmt::format("No valid fingerprint found in:\n{}\n", *output);
|
||||
std::cerr << "No valid fingerprint found in:\n{}\n"_f(output.Stdout);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
@@ -40,20 +40,19 @@ namespace hpcstat::ssh
|
||||
return std::nullopt;
|
||||
else if
|
||||
(
|
||||
auto output = exec
|
||||
auto output = biu::exec
|
||||
(
|
||||
std::filesystem::path(*sshbindir) / "ssh-keygen",
|
||||
{
|
||||
"-Y", "sign", "-q",
|
||||
"-f", fmt::format("{}/keys/{}", *sharedir, Keys[fingerprint].PubkeyFilename),
|
||||
"-Y", "sign", "-q", "-f", "{}/keys/{}"_f(*sharedir, Keys[fingerprint].PubkeyFilename),
|
||||
"-n", "hpcstat@chn.moe", "-"
|
||||
},
|
||||
message
|
||||
);
|
||||
!output
|
||||
)
|
||||
{ std::cerr << fmt::format("Failed to sign message: {}\n", message); return std::nullopt; }
|
||||
else return *output;
|
||||
{ std::cerr << "Failed to sign message: {}\n"_f(message); return {}; }
|
||||
else return output.Stdout;
|
||||
}
|
||||
bool verify(std::string message, std::string signature, std::string fingerprint)
|
||||
{
|
||||
@@ -68,18 +67,18 @@ namespace hpcstat::ssh
|
||||
bf::create_directories(tempdir);
|
||||
auto signaturefile = tempdir / "signature";
|
||||
std::ofstream(signaturefile) << signature;
|
||||
auto result = exec
|
||||
auto result = biu::exec
|
||||
(
|
||||
std::filesystem::path(*sshbindir) / "ssh-keygen",
|
||||
{
|
||||
"-Y", "verify",
|
||||
"-f", fmt::format("{}/keys/{}", *sharedir, Keys[fingerprint].PubkeyFilename),
|
||||
"-f", "{}/keys/{}"_f(*sharedir, Keys[fingerprint].PubkeyFilename),
|
||||
"-n", "hpcstat@chn.moe", "-s", signaturefile.string()
|
||||
},
|
||||
message
|
||||
);
|
||||
std::filesystem::remove_all(tempdir.string());
|
||||
return result.has_value();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
runHook preInstall
|
||||
mkdir -p $out/bin
|
||||
cp build/{ng01,beta} $out/bin
|
||||
ln -s ${src} $out/src
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
}: (mkPnpmPackage.override { inherit nodejs; })
|
||||
{
|
||||
inherit src;
|
||||
extraIntegritySha256."https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.5/aiscript-dev-aiscript-languageserver-0.1.5.tgz" = "1mhnwa8h48bc21f0zv8q93aphiqz9i70r7m4xsa4sd1mlncfgyl7";
|
||||
extraIntegritySha256."https://github.com/aiscript-dev/aiscript-languageserver/releases/download/0.1.6/aiscript-dev-aiscript-languageserver-0.1.6.tgz" = "0092d5r67bhf4xkvrdn4a2rm1drjzy7b5sw8mi7hp4pqvpc20ylr";
|
||||
extraNativeBuildInputs = [ bash nodejs.pkgs.typescript nodejs.pkgs.gulp ];
|
||||
extraAttrs =
|
||||
{
|
||||
@@ -16,6 +16,7 @@
|
||||
export PATH=${lib.makeBinPath [ bash nodejs nodejs.pkgs.pnpm nodejs.pkgs.gulp cypress ]}:$PATH
|
||||
export CYPRESS_RUN_BINARY="${cypress}/bin/Cypress"
|
||||
export NODE_ENV=production
|
||||
export COREPACK_ENABLE_STRICT=0
|
||||
pnpm run migrateandstart
|
||||
'';
|
||||
in
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
version = lib.last (lib.splitString "@" nameAtVersion);
|
||||
name = lib.last (lib.init (lib.splitString "@" nameAtVersion));
|
||||
baseName = lib.last (lib.splitString "/" name);
|
||||
url = "${registry}/${name}/-/${baseName}-${version}.tgz";
|
||||
url = "${registry}/${if name == baseName then "" else "@"}${name}/-/${baseName}-${version}.tgz";
|
||||
tarball = fetchurl { inherit url; sha512 = value.resolution.integrity; };
|
||||
in value // { resolution.tarball = "file:${tarball}"; }
|
||||
else # if value.resolution ? tarball then
|
||||
@@ -63,6 +63,7 @@
|
||||
export HOME=$NIX_BUILD_TOP # Some packages need a writable HOME
|
||||
export npm_config_nodedir=${nodejs}
|
||||
pnpm config set reporter append-only
|
||||
pnpm config set package-manager-strict false
|
||||
cp -f ${patchedLockFile} pnpm-lock.yaml
|
||||
runHook postConfigure
|
||||
'';
|
||||
|
||||
15
local/pkgs/nodejs-with-pnpm9.nix
Normal file
15
local/pkgs/nodejs-with-pnpm9.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{ nodejs, fetchurl }: nodejs.overrideAttrs (prev:
|
||||
{
|
||||
passthru.pkgs = prev.passthru.pkgs.extend (final: prev:
|
||||
{
|
||||
pnpm = prev.pnpm.override
|
||||
{
|
||||
version = "9.1.0";
|
||||
src = fetchurl
|
||||
{
|
||||
url = "https://registry.npmjs.org/pnpm/-/pnpm-9.1.0.tgz";
|
||||
sha512 = "Z/WHmRapKT5c8FnCOFPVcb6vT3U8cH9AyyK+1fsVeMaq07bEEHzLO6CzW+AD62IaFkcayDbIe+tT+dVLtGEnJA==";
|
||||
};
|
||||
};
|
||||
});
|
||||
})
|
||||
@@ -13,6 +13,7 @@
|
||||
''
|
||||
export PATH=${lib.makeBinPath [ bash nodejs nodejs.pkgs.pnpm chromium git ]}:$PATH
|
||||
export CHROMIUM_EXECUTABLE_PATH=chromium
|
||||
export COREPACK_ENABLE_STRICT=0
|
||||
pnpm start
|
||||
'';
|
||||
in
|
||||
|
||||
3
local/pkgs/sbatch-tui/.clangd
Normal file
3
local/pkgs/sbatch-tui/.clangd
Normal file
@@ -0,0 +1,3 @@
|
||||
CompileFlags:
|
||||
Add: [ -Wall, -Wextra, -std=c++23 ]
|
||||
Compiler: g++
|
||||
1
local/pkgs/sbatch-tui/.envrc
Normal file
1
local/pkgs/sbatch-tui/.envrc
Normal file
@@ -0,0 +1 @@
|
||||
use flake .#sbatch-tui
|
||||
27
local/pkgs/sbatch-tui/CMakeLists.txt
Normal file
27
local/pkgs/sbatch-tui/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(sbatch-tui VERSION 0.0.0 LANGUAGES CXX)
|
||||
enable_testing()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message("Setting build type to 'Release' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
find_package(ftxui REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem iostreams)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_package(biu REQUIRED)
|
||||
|
||||
add_executable(sbatch-tui src/main.cpp src/device.cpp)
|
||||
target_compile_features(sbatch-tui PUBLIC cxx_std_23)
|
||||
target_include_directories(sbatch-tui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_link_libraries(sbatch-tui PRIVATE fmt::fmt ftxui::screen ftxui::dom ftxui::component Boost::filesystem
|
||||
range-v3::range-v3 biu::biu)
|
||||
|
||||
install(TARGETS sbatch-tui RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS)
|
||||
message("Imported targets: ${ImportedTargets}")
|
||||
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
|
||||
13
local/pkgs/sbatch-tui/default.nix
Normal file
13
local/pkgs/sbatch-tui/default.nix
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
stdenv, lib, sbatchConfig ? null, substituteAll, runCommand,
|
||||
cmake, pkg-config, ftxui, biu
|
||||
}:
|
||||
stdenv.mkDerivation
|
||||
{
|
||||
name = "sbatch-tui";
|
||||
src = ./.;
|
||||
preConfigure = lib.optionalString (sbatchConfig != null)
|
||||
"cp ${substituteAll ({ src = ./src/device.cpp.template; } // sbatchConfig)} src/device.cpp";
|
||||
buildInputs = [ ftxui biu ];
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
}
|
||||
10
local/pkgs/sbatch-tui/include/sbatch-tui/device.hpp
Normal file
10
local/pkgs/sbatch-tui/include/sbatch-tui/device.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
# pragma once
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
struct Device_t
|
||||
{
|
||||
unsigned CpuMpiThreads, CpuOpenmpThreads;
|
||||
std::vector<std::string> GpuIds;
|
||||
};
|
||||
extern Device_t Device;
|
||||
8
local/pkgs/sbatch-tui/src/device.cpp
Normal file
8
local/pkgs/sbatch-tui/src/device.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
# include <sbatch-tui/device.hpp>
|
||||
|
||||
Device_t Device
|
||||
{
|
||||
.CpuMpiThreads = 1,
|
||||
.CpuOpenmpThreads = 1,
|
||||
.GpuIds = { "4060" }
|
||||
};
|
||||
8
local/pkgs/sbatch-tui/src/device.cpp.template
Normal file
8
local/pkgs/sbatch-tui/src/device.cpp.template
Normal file
@@ -0,0 +1,8 @@
|
||||
# include <sbatch-tui/device.hpp>
|
||||
|
||||
Device_t Device
|
||||
{
|
||||
.CpuMpiThreads = @cpuMpiThreads@,
|
||||
.CpuOpenmpThreads = @cpuOpenmpThreads@,
|
||||
.GpuIds = { @gpuIds@ }
|
||||
};
|
||||
160
local/pkgs/sbatch-tui/src/main.cpp
Normal file
160
local/pkgs/sbatch-tui/src/main.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
# include <filesystem>
|
||||
# include <ftxui/component/component.hpp>
|
||||
# include <ftxui/component/component_options.hpp>
|
||||
# include <ftxui/component/screen_interactive.hpp>
|
||||
# include <boost/algorithm/string.hpp>
|
||||
# include <range/v3/view.hpp>
|
||||
# include <sbatch-tui/device.hpp>
|
||||
# include <biu.hpp>
|
||||
|
||||
using namespace biu::literals;
|
||||
|
||||
int main()
|
||||
{
|
||||
// 需要绑定到界面上的变量
|
||||
struct
|
||||
{
|
||||
int vasp_version_selected = 0;
|
||||
std::vector<std::string> vasp_version_entries = { "std", "gam", "ncl" };
|
||||
int device_type_selected = 0;
|
||||
std::vector<std::string> device_type_entries = { "any single GPU", "manually select GPU", "CPU" };
|
||||
std::deque<bool> device_selected = std::deque<bool>(Device.GpuIds.size(), false);
|
||||
std::vector<std::string> device_entries = Device.GpuIds;
|
||||
std::string job_name = std::filesystem::current_path().filename().string();
|
||||
std::string output_file = "output.txt";
|
||||
std::string mpi_threads = std::to_string(Device.CpuMpiThreads);
|
||||
std::string openmp_threads = std::to_string(Device.CpuOpenmpThreads);
|
||||
|
||||
std::string user_command;
|
||||
std::string submit_command;
|
||||
} state;
|
||||
|
||||
// 为组件增加标题栏和分割线
|
||||
auto with_title = [](std::string title)
|
||||
{
|
||||
return [title](ftxui::Element element)
|
||||
{
|
||||
return ftxui::vbox
|
||||
(ftxui::text(title) | ftxui::bgcolor(ftxui::Color::Blue), element, ftxui::separatorLight());
|
||||
};
|
||||
};
|
||||
// 为组件增加空白以填充界面
|
||||
auto with_padding = [](ftxui::Element element) -> ftxui::Element
|
||||
{
|
||||
auto empty = ftxui::emptyElement() | ftxui::flex_grow;
|
||||
return ftxui::vbox(empty, ftxui::hbox(empty, element | ftxui::center, empty), empty);
|
||||
};
|
||||
// 在组件左边增加分割线
|
||||
auto with_separator = [](ftxui::Element element)
|
||||
{ return ftxui::hbox(ftxui::separatorLight(), element); };
|
||||
// 在组件左边增加小标题
|
||||
auto with_subtitle = [](std::string title)
|
||||
{ return [title](ftxui::Element element) { return ftxui::hbox(ftxui::text(title), element); }; };
|
||||
|
||||
// 构建界面
|
||||
auto screen = ftxui::ScreenInteractive::Fullscreen();
|
||||
auto request_interface = ftxui::Container::Vertical
|
||||
({
|
||||
ftxui::Menu(&state.vasp_version_entries, &state.vasp_version_selected)
|
||||
| with_title("Select VASP version:"),
|
||||
ftxui::Container::Horizontal
|
||||
({
|
||||
ftxui::Menu(&state.device_type_entries, &state.device_type_selected),
|
||||
ftxui::Container::Vertical([&]
|
||||
{
|
||||
std::vector<std::shared_ptr<ftxui::ComponentBase>> devices;
|
||||
auto checkbox_option = ftxui::CheckboxOption::Simple();
|
||||
checkbox_option.transform = [](const ftxui::EntryState& s)
|
||||
{
|
||||
auto prefix = ftxui::text(s.state ? "[X] " : "[ ] ");
|
||||
auto t = ftxui::text(s.label);
|
||||
if (s.active) t |= ftxui::bold;
|
||||
if (s.focused) t |= ftxui::inverted;
|
||||
return ftxui::hbox({prefix, t});
|
||||
};
|
||||
for (int i = 0; i < state.device_selected.size(); i++)
|
||||
devices.push_back(ftxui::Checkbox
|
||||
(state.device_entries[i], &state.device_selected[i], checkbox_option));
|
||||
return devices;
|
||||
}()) | with_separator | ftxui::Maybe([&]{ return state.device_type_selected == 1; }),
|
||||
ftxui::Container::Vertical
|
||||
({
|
||||
ftxui::Input(&state.mpi_threads) | ftxui::size(ftxui::WIDTH, ftxui::GREATER_THAN, 3)
|
||||
| with_subtitle("MPI threads: "),
|
||||
ftxui::Input(&state.openmp_threads) | ftxui::size(ftxui::WIDTH, ftxui::GREATER_THAN, 3)
|
||||
| with_subtitle("OpenMP threads: ")
|
||||
}) | with_separator | ftxui::Maybe([&]{ return state.device_type_selected == 2; }),
|
||||
}) | with_title("Select device:"),
|
||||
ftxui::Input(&state.job_name) | with_title("Job name:"),
|
||||
ftxui::Input(&state.output_file) | with_title("Output file:"),
|
||||
ftxui::Container::Horizontal
|
||||
({
|
||||
ftxui::Button("Continue",
|
||||
[&]{ state.user_command = "continue"; screen.ExitLoopClosure()(); }),
|
||||
ftxui::Button("Quit",
|
||||
[&]{ state.user_command = "quit"; screen.ExitLoopClosure()(); })
|
||||
})
|
||||
}) | ftxui::borderHeavy | with_padding;
|
||||
auto confirm_interface = ftxui::Container::Vertical
|
||||
({
|
||||
ftxui::Input(&state.submit_command, "", ftxui::InputOption{.multiline = true})
|
||||
| with_title("Double check & modify submit command:"),
|
||||
ftxui::Container::Horizontal
|
||||
({
|
||||
ftxui::Button("Submit",
|
||||
[&]{state.user_command = "submit"; screen.ExitLoopClosure()();}),
|
||||
ftxui::Button("Quit",
|
||||
[&]{state.user_command = "quit"; screen.ExitLoopClosure()();}),
|
||||
ftxui::Button("Back",
|
||||
[&]{state.user_command = "back"; screen.ExitLoopClosure()();})
|
||||
})
|
||||
}) | ftxui::borderHeavy | with_padding;
|
||||
|
||||
// 实际投递任务
|
||||
auto submit = [](std::string submit_command)
|
||||
{
|
||||
// replace \n with space
|
||||
boost::replace_all(submit_command, "\n", " ");
|
||||
biu::exec<{.DirectStdout = true, .DirectStderr = true, .SearchPath = true}>
|
||||
("sh", { "-c", submit_command });
|
||||
};
|
||||
|
||||
// 进入事件循环
|
||||
while (true)
|
||||
{
|
||||
screen.Loop(request_interface);
|
||||
if (state.user_command == "quit") return EXIT_FAILURE;
|
||||
else if (state.device_type_selected == 0)
|
||||
state.submit_command =
|
||||
"sbatch --ntasks=1\n--gpus=1\n--job-name='{}'\n--output='{}'\nvasp-nvidia-{}"_f
|
||||
(state.job_name, state.output_file, state.vasp_version_entries[state.vasp_version_selected]);
|
||||
else if (state.device_type_selected == 2)
|
||||
state.submit_command =
|
||||
"sbatch --ntasks={}\n--cpus-per-task={}\n--hint=nomultithread\n--job-name='{}'\n--output='{}'"
|
||||
"\nvasp-intel-{}"_f
|
||||
(
|
||||
state.mpi_threads, state.openmp_threads, state.job_name, state.output_file,
|
||||
state.vasp_version_entries[state.vasp_version_selected]
|
||||
);
|
||||
else
|
||||
{
|
||||
std::vector<std::string> selected_gpus;
|
||||
for (int i = 0; i < state.device_selected.size(); i++)
|
||||
if (state.device_selected[i]) selected_gpus.push_back(state.device_entries[i]);
|
||||
state.submit_command =
|
||||
"sbatch --ntasks={}\n--gres={}\n--job-name='{}'\n--output='{}'\nvasp-nvidia-{}"_f
|
||||
(
|
||||
selected_gpus.size(),
|
||||
selected_gpus
|
||||
| ranges::views::transform([](auto& entry) { return "gpu:{}:1"_f(entry); })
|
||||
| ranges::views::join(',') | ranges::to<std::string>,
|
||||
state.job_name, state.output_file, state.vasp_version_entries[state.vasp_version_selected]
|
||||
);
|
||||
}
|
||||
screen.Loop(confirm_interface);
|
||||
if (state.user_command == "quit") return EXIT_FAILURE;
|
||||
else if (state.user_command == "back") continue;
|
||||
submit(state.submit_command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
1
local/pkgs/ufo/.gitignore
vendored
Normal file
1
local/pkgs/ufo/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
test
|
||||
33
local/pkgs/ufo/CMakeLists.txt
Normal file
33
local/pkgs/ufo/CMakeLists.txt
Normal file
@@ -0,0 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
project(ufo VERSION 0 LANGUAGES CXX)
|
||||
enable_testing()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message("Setting build type to 'Release' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
find_package(yaml-cpp REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(concurrencpp REQUIRED)
|
||||
find_package(HighFive REQUIRED)
|
||||
find_package(TBB REQUIRED)
|
||||
find_package(glad REQUIRED)
|
||||
find_package(Matplot++ REQUIRED)
|
||||
find_path(ZPP_BITS_INCLUDE_DIR zpp_bits.h REQUIRED)
|
||||
|
||||
add_executable(ufo src/solver.cpp src/fold.cpp src/unfold.cpp src/plot.cpp src/main.cpp)
|
||||
target_include_directories(ufo PRIVATE ${PROJECT_SOURCE_DIR}/include ${ZPP_BITS_INCLUDE_DIR})
|
||||
target_link_libraries(ufo PRIVATE
|
||||
yaml-cpp Eigen3::Eigen fmt::fmt concurrencpp::concurrencpp HighFive_HighFive TBB::tbb Matplot++::matplot
|
||||
Matplot++::matplot_opengl)
|
||||
target_compile_features(ufo PRIVATE cxx_std_23)
|
||||
|
||||
install(TARGETS ufo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
get_property(ImportedTargets DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY IMPORTED_TARGETS)
|
||||
message("Imported targets: ${ImportedTargets}")
|
||||
message("List of compile features: ${CMAKE_CXX_COMPILE_FEATURES}")
|
||||
10
local/pkgs/ufo/default.nix
Normal file
10
local/pkgs/ufo/default.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
stdenv, cmake, pkg-config,
|
||||
yaml-cpp, eigen, fmt, concurrencpp, highfive, tbb, glad, matplotplusplus, biu, zpp-bits
|
||||
}: stdenv.mkDerivation
|
||||
{
|
||||
name = "ufo";
|
||||
src = ./.;
|
||||
buildInputs = [ yaml-cpp eigen fmt concurrencpp highfive tbb glad matplotplusplus biu zpp-bits ];
|
||||
nativeBuildInputs = [ cmake pkg-config ];
|
||||
}
|
||||
37
local/pkgs/ufo/include/ufo/fold.hpp
Normal file
37
local/pkgs/ufo/include/ufo/fold.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
# pragma once
|
||||
# include <ufo/solver.hpp>
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
class FoldSolver : public Solver
|
||||
{
|
||||
public:
|
||||
struct InputType
|
||||
{
|
||||
Eigen::Vector<unsigned, 3> SuperCellMultiplier;
|
||||
std::optional<Eigen::Matrix<double, 3, 3>> SuperCellDeformation;
|
||||
std::vector<Eigen::Vector3d> Qpoints;
|
||||
DataFile OutputFile;
|
||||
|
||||
InputType(std::string config_file);
|
||||
};
|
||||
struct OutputType
|
||||
{
|
||||
std::vector<Eigen::Vector3d> Qpoints;
|
||||
void write(std::string filename) const;
|
||||
};
|
||||
protected:
|
||||
InputType Input_;
|
||||
std::optional<OutputType> Output_;
|
||||
public:
|
||||
FoldSolver(std::string config_file);
|
||||
FoldSolver& operator()() override;
|
||||
// return value: QpointInReciprocalSuperCellByReciprocalSuperCell
|
||||
static Eigen::Vector3d fold
|
||||
(
|
||||
Eigen::Vector3d qpoint_in_reciprocal_primitive_cell_by_reciprocal_primitive_cell,
|
||||
Eigen::Vector<unsigned, 3> super_cell_multiplier,
|
||||
std::optional<Eigen::Matrix<double, 3, 3>> super_cell_deformation
|
||||
);
|
||||
};
|
||||
}
|
||||
77
local/pkgs/ufo/include/ufo/plot.hpp
Normal file
77
local/pkgs/ufo/include/ufo/plot.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
# pragma once
|
||||
# include <ufo/unfold.hpp>
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
class PlotSolver : public Solver
|
||||
{
|
||||
public:
|
||||
struct InputType
|
||||
{
|
||||
Eigen::Matrix3d PrimativeCell;
|
||||
|
||||
struct FigureConfigType
|
||||
{
|
||||
std::vector<std::vector<Eigen::Vector3d>> Qpoints;
|
||||
std::pair<unsigned, unsigned> Resolution;
|
||||
std::pair<double, double> Range;
|
||||
std::optional<std::vector<double>> YTicks;
|
||||
DataFile PictureFile;
|
||||
std::optional<std::vector<DataFile>> DataFiles;
|
||||
};
|
||||
std::vector<FigureConfigType> Figures;
|
||||
|
||||
struct UnfoldedDataType : public UnfoldSolver::OutputType
|
||||
{
|
||||
UnfoldedDataType(std::string filename);
|
||||
UnfoldedDataType() = default;
|
||||
};
|
||||
DataFile UnfoldedDataFile;
|
||||
UnfoldedDataType UnfoldedData;
|
||||
|
||||
InputType(std::string config_file);
|
||||
};
|
||||
struct OutputType
|
||||
{
|
||||
std::vector<std::vector<double>> Values;
|
||||
std::vector<double> XTicks;
|
||||
std::vector<double> YTicks;
|
||||
std::pair<unsigned, unsigned> Resolution;
|
||||
std::pair<double, double> Range;
|
||||
|
||||
OutputType() = default;
|
||||
const OutputType& write(std::string filename, std::string format) const;
|
||||
using serialize = zpp::bits::members<5>;
|
||||
};
|
||||
protected:
|
||||
InputType Input_;
|
||||
std::optional<std::vector<OutputType>> Output_;
|
||||
public:
|
||||
PlotSolver(std::string config_file);
|
||||
PlotSolver& operator()() override;
|
||||
|
||||
// 根据 q 点路径, 搜索要使用的 q 点
|
||||
static std::vector<std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>> search_qpoints
|
||||
(
|
||||
const std::pair<Eigen::Vector3d, Eigen::Vector3d>& path,
|
||||
const decltype(InputType::UnfoldedDataType::QpointData)& available_qpoints,
|
||||
double threshold, bool exclude_endpoint = false
|
||||
);
|
||||
// 根据搜索到的 q 点, 计算每个点的数值
|
||||
static std::tuple<std::vector<std::vector<double>>, std::vector<double>> calculate_values
|
||||
(
|
||||
const Eigen::Matrix3d primative_cell,
|
||||
const std::vector<std::pair<Eigen::Vector3d, Eigen::Vector3d>>& path,
|
||||
const std::vector<std::vector<std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>>>& qpoints,
|
||||
const decltype(InputType::FigureConfigType::Resolution)& resolution,
|
||||
const decltype(InputType::FigureConfigType::Range)& range
|
||||
);
|
||||
// 根据数值, 画图
|
||||
static void plot
|
||||
(
|
||||
const std::vector<std::vector<double>>& values,
|
||||
const std::string& filename,
|
||||
const std::vector<double>& x_ticks, const std::vector<double>& y_ticks
|
||||
);
|
||||
};
|
||||
}
|
||||
141
local/pkgs/ufo/include/ufo/solver.hpp
Normal file
141
local/pkgs/ufo/include/ufo/solver.hpp
Normal file
@@ -0,0 +1,141 @@
|
||||
# pragma once
|
||||
# include <iostream>
|
||||
# include <array>
|
||||
# include <numbers>
|
||||
# include <numeric>
|
||||
# include <fstream>
|
||||
# include <optional>
|
||||
# include <array>
|
||||
# include <utility>
|
||||
# include <execution>
|
||||
# include <syncstream>
|
||||
# include <any>
|
||||
# include <map>
|
||||
# include <vector>
|
||||
# include <span>
|
||||
# include <yaml-cpp/yaml.h>
|
||||
# include <Eigen/Dense>
|
||||
# include <concurrencpp/concurrencpp.h>
|
||||
# include <fmt/format.h>
|
||||
# include <fmt/std.h>
|
||||
# include <fmt/ranges.h>
|
||||
# include <highfive/H5File.hpp>
|
||||
# include <zpp_bits.h>
|
||||
# include <matplot/matplot.h>
|
||||
# include <matplot/backend/opengl.h>
|
||||
|
||||
// 在相位中, 约定为使用 $\exp (2 \pi i \vec{q} \cdot \vec{r})$ 来表示原子的运动状态
|
||||
// (而不是 $\exp (-2 \pi i \vec{q} \cdot \vec{r})$)
|
||||
// 一些书定义的倒格矢中包含了 $2 \pi$ 的部分, 我们这里约定不包含这部分.
|
||||
// 也就是说, 正格子与倒格子的转置相乘, 得到单位矩阵.
|
||||
|
||||
namespace Eigen
|
||||
{
|
||||
constexpr inline auto serialize(auto & archive, Eigen::Matrix3d& matrix)
|
||||
{ return archive(std::span(matrix.data(), matrix.size())); }
|
||||
constexpr inline auto serialize(auto & archive, const Eigen::Matrix3d& matrix)
|
||||
{ return archive(std::span(matrix.data(), matrix.size())); }
|
||||
constexpr inline auto serialize(auto & archive, Eigen::Vector3d& vector)
|
||||
{ return archive(std::span(vector.data(), vector.size())); }
|
||||
constexpr inline auto serialize(auto & archive, const Eigen::Vector3d& vector)
|
||||
{ return archive(std::span(vector.data(), vector.size())); }
|
||||
}
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
using namespace std::literals;
|
||||
struct PhonopyComplex { double r, i; };
|
||||
inline HighFive::CompoundType create_compound_complex()
|
||||
{ return {{ "r", HighFive::AtomicType<double>{}}, {"i", HighFive::AtomicType<double>{}}}; }
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
template <typename T> struct SpecializationOfBitsMembersHelper : std::false_type {};
|
||||
template <std::size_t N> struct SpecializationOfBitsMembersHelper<zpp::bits::members<N>> : std::true_type {};
|
||||
}
|
||||
template <typename T> concept ZppSerializable
|
||||
= requires() { detail_::SpecializationOfBitsMembersHelper<T>::value == true; };
|
||||
|
||||
class Solver
|
||||
{
|
||||
public:
|
||||
virtual Solver& operator()() = 0;
|
||||
virtual ~Solver() = default;
|
||||
|
||||
static concurrencpp::generator<std::pair<Eigen::Vector<unsigned, 3>, unsigned>>
|
||||
triplet_sequence(Eigen::Vector<unsigned, 3> range);
|
||||
|
||||
template <ZppSerializable T> inline static void zpp_write(const T& object, std::string filename)
|
||||
{
|
||||
auto [data, out] = zpp::bits::data_out();
|
||||
out(object).or_throw();
|
||||
static_assert(sizeof(char) == sizeof(std::byte));
|
||||
std::ofstream file(filename, std::ios::binary | std::ios::out);
|
||||
file.exceptions(std::ios::badbit | std::ios::failbit);
|
||||
file.write(reinterpret_cast<const char*>(data.data()), data.size());
|
||||
}
|
||||
template <ZppSerializable T> inline static T zpp_read(std::string filename)
|
||||
{
|
||||
auto input = std::ifstream(filename, std::ios::binary | std::ios::in);
|
||||
input.exceptions(std::ios::badbit | std::ios::failbit);
|
||||
static_assert(sizeof(std::byte) == sizeof(char));
|
||||
std::vector<std::byte> data;
|
||||
{
|
||||
std::vector<char> string(std::istreambuf_iterator<char>(input), {});
|
||||
data.assign
|
||||
(
|
||||
reinterpret_cast<std::byte*>(string.data()),
|
||||
reinterpret_cast<std::byte*>(string.data() + string.size())
|
||||
);
|
||||
}
|
||||
auto in = zpp::bits::in(data);
|
||||
T output;
|
||||
in(output).or_throw();
|
||||
return output;
|
||||
}
|
||||
|
||||
class Hdf5file
|
||||
{
|
||||
public:
|
||||
inline Hdf5file& open_for_read(std::string filename)
|
||||
{
|
||||
File_ = HighFive::File(filename, HighFive::File::ReadOnly);
|
||||
return *this;
|
||||
}
|
||||
inline Hdf5file& open_for_write(std::string filename)
|
||||
{
|
||||
File_ = HighFive::File(filename, HighFive::File::ReadWrite | HighFive::File::Create
|
||||
| HighFive::File::Truncate);
|
||||
return *this;
|
||||
}
|
||||
template <typename T> inline Hdf5file& read(T& object, std::string name)
|
||||
{
|
||||
object = File_->getDataSet(name).read<std::remove_cvref_t<decltype(object)>>();
|
||||
return *this;
|
||||
}
|
||||
template <typename T> inline Hdf5file& write(const T& object, std::string name)
|
||||
{
|
||||
File_->createDataSet(name, object);
|
||||
return *this;
|
||||
}
|
||||
protected:
|
||||
std::optional<HighFive::File> File_;
|
||||
};
|
||||
|
||||
struct DataFile
|
||||
{
|
||||
std::string Filename;
|
||||
std::string Format;
|
||||
std::map<std::string, std::any> ExtraParameters;
|
||||
inline DataFile() = default;
|
||||
DataFile
|
||||
(
|
||||
YAML::Node node, std::set<std::string> supported_format,
|
||||
std::string config_file, bool allow_same_as_config_file = false
|
||||
);
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
HIGHFIVE_REGISTER_TYPE(ufo::PhonopyComplex, ufo::create_compound_complex)
|
||||
164
local/pkgs/ufo/include/ufo/unfold.hpp
Normal file
164
local/pkgs/ufo/include/ufo/unfold.hpp
Normal file
@@ -0,0 +1,164 @@
|
||||
# pragma once
|
||||
# include <ufo/solver.hpp>
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
// 反折叠的原理: 将超胞中的原子运动状态, 投影到一组平面波构成的基矢中.
|
||||
// 每一个平面波的波矢由两部分相加得到: 一部分是单胞倒格子的整数倍, 所取的个数有一定任意性, 论文中建议取大约单胞中原子个数那么多个;
|
||||
// 对于没有缺陷的情况, 取一个应该就足够了.
|
||||
// 另一部分是超胞倒格子的整数倍, 取 n 个, n 为超胞对应的单胞的倍数, 其实也就是倒空间中单胞对应倒格子中超胞的格点.
|
||||
// 只要第一部分取得足够多, 那么单胞中原子的状态就可以完全被这些平面波描述.
|
||||
// 将超胞中原子的运动状态投影到这些基矢上, 计算出投影的系数, 就可以将超胞的原子运动状态分解到单胞中的多个 q 点上.
|
||||
class UnfoldSolver : public Solver
|
||||
{
|
||||
public:
|
||||
struct InputType
|
||||
{
|
||||
// 单胞的三个格矢,每行表示一个格矢的坐标,单位为埃
|
||||
Eigen::Matrix3d PrimativeCell;
|
||||
// 单胞到超胞的格矢转换时用到的矩阵
|
||||
// SuperCellMultiplier 是一个三维列向量且各个元素都是整数,表示单胞在各个方向扩大到多少倍之后,可以得到和超胞一样的体积
|
||||
// SuperCsolver.hpp>mation 是一个行列式为 1 的矩阵,它表示经过 SuperCellMultiplier 扩大后,还需要怎样的变换才能得到超胞
|
||||
// SuperCell = (SuperCellDeformation * SuperCellMultiplier.asDiagonal()) * PrimativeCell
|
||||
// ReciprocalPrimativeCell = (SuperCellDeformation * SuperCellMultiplier.asDiagonal()).transpose()
|
||||
// * ReciprocalSuperCell
|
||||
// Position = PositionToCell(line vector) * Cell
|
||||
// InversePosition = InversePositionToCell(line vector) * ReciprocalCell
|
||||
// PositionToSuperCell(line vector) * SuperCell = PositionToPrimativeCell(line vector) * PrimativeCell
|
||||
// ReciprocalPositionToSuperCell(line vector) * ReciprocalSuperCell
|
||||
// = ReciprocalPositionToPrimativeCell(line vector) * ReciprocalPrimativeCell
|
||||
Eigen::Vector<unsigned, 3> SuperCellMultiplier;
|
||||
std::optional<Eigen::Matrix<double, 3, 3>> SuperCellDeformation;
|
||||
// 在单胞内取几个平面波的基矢
|
||||
Eigen::Vector<unsigned, 3> PrimativeCellBasisNumber;
|
||||
|
||||
// 从哪个文件读入 AtomPosition, 以及这个文件的格式, 格式可选值包括 "yaml"
|
||||
DataFile AtomPositionInputFile;
|
||||
// 从哪个文件读入 QpointData, 以及这个文件的格式, 格式可选值包括 "yaml" 和 "hdf5"
|
||||
DataFile QpointDataInputFile;
|
||||
|
||||
// 超胞中原子的坐标,每行表示一个原子的坐标,单位为埃
|
||||
Eigen::MatrixX3d AtomPosition;
|
||||
// 关于各个 Q 点的数据
|
||||
struct QpointDataType
|
||||
{
|
||||
// Q 点的坐标,单位为超胞的倒格矢
|
||||
Eigen::Vector3d Qpoint;
|
||||
|
||||
// 关于这个 Q 点上各个模式的数据
|
||||
struct ModeDataType
|
||||
{
|
||||
// 模式的频率,单位为 THz
|
||||
double Frequency;
|
||||
// 模式中各个原子的运动状态
|
||||
// 这个数据是这样得到的: phonopy 输出的动态矩阵的 eigenvector 乘以 $\exp(-2 \pi i \vec q \cdot \vec r)$
|
||||
// 这个数据可以认为是原子位移中, 关于超胞有周期性的那一部分, 再乘以原子质量的开方.
|
||||
// 这个数据在读入后会被立即归一化.
|
||||
Eigen::MatrixX3cd AtomMovement;
|
||||
};
|
||||
std::vector<ModeDataType> ModeData;
|
||||
};
|
||||
std::vector<QpointDataType> QpointData;
|
||||
|
||||
// 输出到哪些文件, 以及使用怎样的格式, 格式可选值包括:
|
||||
// yaml: 使用 yaml 格式输出
|
||||
// yaml-human-readable: 使用 yaml 格式输出, 但是输出的结果更适合人类阅读,
|
||||
// 包括合并相近的模式, 去除权重过小的模式, 限制输出的小数位数.
|
||||
// zpp: 使用 zpp-bits 序列化, 可以直接被 plot.cpp 读取
|
||||
std::vector<DataFile> QpointDataOutputFile;
|
||||
|
||||
// 从文件中读取输入 (包括一个较小的配置文件, 和一个 hdf5 或者一个 yaml 文件), 文件中应当包含:
|
||||
// 单胞的格矢: PrimativeCell 单位为埃 直接从 phonopy 的输出中复制
|
||||
// 超胞的倍数: SuperCellMultiplier 手动输入, 为一个包含三个整数的数组
|
||||
// 超胞的变形: SuperCellDeformation 手动输入, 为一个三阶方阵
|
||||
// 平面波的基矢个数: PrimativeCellBasisNumber 手动输入, 为一个包含三个整数的数组
|
||||
// 另外还有一个文件, 直接将 phonopy 的输出复制过来即可, 如果是 yaml, 应该包含下面的内容:
|
||||
// 超胞中原子的坐标: points[*].coordinates 单位为超胞的格矢 直接从 phonopy 的输出中复制
|
||||
// 各个 Q 点的坐标: phonon[*].q-position 单位为超胞的倒格子的格矢 直接从 phonopy 的输出中复制
|
||||
// 各个模式的频率: phonon[*].band[*].frequency 单位为 THz 直接从 phonopy 的输出中复制
|
||||
// 各个模式的原子运动状态: phonon[*].band[*].eigenvector 直接从 phonopy 的输出中复制
|
||||
// 文件中可以有多余的项目, 多余的项目不管.
|
||||
InputType(std::string filename);
|
||||
};
|
||||
struct OutputType
|
||||
{
|
||||
// 关于各个 Q 点的数据
|
||||
struct QpointDataType
|
||||
{
|
||||
// Q 点的坐标,单位为单胞的倒格矢
|
||||
Eigen::Vector3d Qpoint;
|
||||
|
||||
// 来源于哪个 Q 点, 单位为超胞的倒格矢
|
||||
Eigen::Vector3d Source;
|
||||
std::size_t SourceIndex_;
|
||||
|
||||
// 关于这个 Q 点上各个模式的数据
|
||||
struct ModeDataType
|
||||
{
|
||||
// 模式的频率,单位为 THz
|
||||
double Frequency;
|
||||
// 模式的权重
|
||||
double Weight;
|
||||
};
|
||||
std::vector<ModeDataType> ModeData;
|
||||
};
|
||||
std::vector<QpointDataType> QpointData;
|
||||
|
||||
void write(decltype(InputType::QpointDataOutputFile) output_files) const;
|
||||
void write(std::string filename, std::string format, unsigned percision = 10) const;
|
||||
|
||||
using serialize = zpp::bits::members<1>;
|
||||
|
||||
virtual ~OutputType() = default;
|
||||
};
|
||||
|
||||
// 第一层是不同的 sub qpoint, 第二层是单胞内不同的平面波
|
||||
using BasisType = std::vector<std::vector<Eigen::VectorXcd>>;
|
||||
protected:
|
||||
InputType Input_;
|
||||
std::optional<OutputType> Output_;
|
||||
std::optional<BasisType> Basis_;
|
||||
|
||||
// 第一层是不同的模式, 第二层是不同的 sub qpoint
|
||||
using ProjectionCoefficientType_ = std::vector<std::vector<double>>;
|
||||
|
||||
public:
|
||||
UnfoldSolver(std::string config_file);
|
||||
UnfoldSolver& operator()() override;
|
||||
|
||||
// 构建基
|
||||
// 每个 q 点对应的一组 sub qpoint。不同的 q 点所对应的 sub qpoint 是不一样的,但 sub qpoint 与 q 点的相对位置一致。
|
||||
// 这里 xyz_of_diff_of_sub_qpoint 即表示这个相对位置。
|
||||
// 由于基只与这个相对位置有关(也就是说,不同 q 点的基是一样的),因此可以先计算出所有的基,这样降低计算量。
|
||||
// 外层下标对应超胞倒格子的整数倍那部分(第二部分), 也就是不同的 sub qpoint
|
||||
// 内层下标对应单胞倒格子的整数倍那部分(第一部分), 也就是 sub qpoint 上的不同平面波(取的数量越多,结果越精确)
|
||||
static BasisType construct_basis
|
||||
(
|
||||
const decltype(InputType::PrimativeCell)& primative_cell,
|
||||
const decltype(InputType::SuperCellMultiplier)& super_cell_multiplier,
|
||||
const decltype(InputType::PrimativeCellBasisNumber)&
|
||||
primative_cell_basis_number,
|
||||
const decltype(InputType::AtomPosition)& atom_position
|
||||
);
|
||||
|
||||
// 计算投影系数, 是反折叠的核心步骤
|
||||
ProjectionCoefficientType_ construct_projection_coefficient
|
||||
(
|
||||
const BasisType& basis,
|
||||
const std::vector<std::reference_wrapper<const decltype
|
||||
(InputType::QpointDataType::ModeDataType::AtomMovement)>>& mode_data,
|
||||
std::atomic<unsigned>& number_of_finished_modes
|
||||
);
|
||||
|
||||
OutputType construct_output
|
||||
(
|
||||
const decltype(InputType::SuperCellMultiplier)& super_cell_multiplier,
|
||||
const decltype(InputType::SuperCellDeformation)& super_cell_deformation,
|
||||
const std::vector<std::reference_wrapper<const decltype
|
||||
(InputType::QpointDataType::Qpoint)>>& meta_qpoint_by_reciprocal_super_cell,
|
||||
const std::vector<std::vector<std::reference_wrapper<const decltype
|
||||
(InputType::QpointDataType::ModeDataType::Frequency)>>>& frequency,
|
||||
const ProjectionCoefficientType_& projection_coefficient
|
||||
);
|
||||
};
|
||||
}
|
||||
86
local/pkgs/ufo/src/fold.cpp
Normal file
86
local/pkgs/ufo/src/fold.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
# include <ufo/fold.hpp>
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
FoldSolver::InputType::InputType(std::string config_file)
|
||||
{
|
||||
auto input = YAML::LoadFile(config_file);
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
SuperCellMultiplier(i) = input["SuperCellMultiplier"][i].as<unsigned>();
|
||||
if (input["SuperCellDeformation"])
|
||||
{
|
||||
SuperCellDeformation.emplace();
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
for (unsigned j = 0; j < 3; j++)
|
||||
(*SuperCellDeformation)(i, j) = input["SuperCellDeformation"][i][j].as<double>();
|
||||
}
|
||||
for (auto& qpoint : input["Qpoints"].as<std::vector<std::vector<double>>>())
|
||||
Qpoints.push_back(Eigen::Vector3d
|
||||
{{qpoint.at(0)}, {qpoint.at(1)}, {qpoint.at(2)}});
|
||||
OutputFile = DataFile(input["OutputFile"], {"yaml"}, config_file);
|
||||
}
|
||||
void FoldSolver::OutputType::write(std::string filename) const
|
||||
{
|
||||
std::ofstream(filename) << [&]
|
||||
{
|
||||
std::stringstream print;
|
||||
print << "Qpoints:\n";
|
||||
for (auto& qpoint : Qpoints)
|
||||
print << fmt::format(" - [ {:.8f}, {:.8f}, {:.8f} ]\n", qpoint(0), qpoint(1), qpoint(2));
|
||||
return print.str();
|
||||
}();
|
||||
}
|
||||
|
||||
FoldSolver::FoldSolver(std::string config_file) : Input_(config_file) {}
|
||||
FoldSolver& FoldSolver::operator()()
|
||||
{
|
||||
if (!Output_)
|
||||
{
|
||||
Output_.emplace();
|
||||
for (auto& qpoint : Input_.Qpoints)
|
||||
Output_->Qpoints.push_back(fold
|
||||
(
|
||||
qpoint, Input_.SuperCellMultiplier,
|
||||
Input_.SuperCellDeformation
|
||||
));
|
||||
}
|
||||
Output_->write(Input_.OutputFile.Filename);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Eigen::Vector3d FoldSolver::fold
|
||||
(
|
||||
Eigen::Vector3d qpoint_in_reciprocal_primitive_cell_by_reciprocal_primitive_cell,
|
||||
Eigen::Vector<unsigned, 3> super_cell_multiplier,
|
||||
std::optional<Eigen::Matrix<double, 3, 3>> super_cell_deformation
|
||||
)
|
||||
{
|
||||
// 首先需要将 q 点转移到 ModifiedSuperCell 的倒格子中
|
||||
// 将 q 点坐标扩大, 然后取小数部分, 就可以了
|
||||
auto qpoint_by_reciprocal_modified_super_cell = super_cell_multiplier.cast<double>().asDiagonal()
|
||||
* qpoint_in_reciprocal_primitive_cell_by_reciprocal_primitive_cell;
|
||||
auto qpoint_in_reciprocal_modified_super_cell_by_reciprocal_modified_super_cell =
|
||||
(qpoint_by_reciprocal_modified_super_cell.array() - qpoint_by_reciprocal_modified_super_cell.array().floor())
|
||||
.matrix();
|
||||
if (!super_cell_deformation)
|
||||
return qpoint_in_reciprocal_modified_super_cell_by_reciprocal_modified_super_cell;
|
||||
/*
|
||||
对 q 点平移数个 SupreCell, 直到它落在超胞的倒格子中
|
||||
这等价于直接将 q 点坐标用 SuperCell 的倒格子表示, 然后取小数部分.
|
||||
ModifiedSuperCell = SuperCellMultiplier * PrimativeCell
|
||||
SuperCell = SuperCellDeformation * ModifiedSuperCell
|
||||
ReciprocalModifiedSuperCell = ModifiedSuperCell.inverse().transpose()
|
||||
ReciprocalSuperCell = SuperCell.inverse().transpose()
|
||||
Qpoint = QpointByReciprocalModifiedSuperCell.transpose() * ReciprocalModifiedSuperCell
|
||||
Qpoint = QpointByReciprocalSuperCell.transpose() * ReciprocalSuperCell
|
||||
整理可以得到:
|
||||
QpointByReciprocalSuperCell = SuperCellDeformation * QpointByReciprocalModifiedSuperCell
|
||||
*/
|
||||
auto qpoint_in_reciprocal_modified_super_cell_by_reciprocal_super_cell =
|
||||
(*super_cell_deformation * qpoint_in_reciprocal_modified_super_cell_by_reciprocal_modified_super_cell).eval();
|
||||
auto qpoint_in_reciprocal_super_cell_by_reciprocal_super_cell =
|
||||
qpoint_in_reciprocal_modified_super_cell_by_reciprocal_super_cell.array()
|
||||
- qpoint_in_reciprocal_modified_super_cell_by_reciprocal_super_cell.array().floor();
|
||||
return qpoint_in_reciprocal_super_cell_by_reciprocal_super_cell;
|
||||
}
|
||||
}
|
||||
17
local/pkgs/ufo/src/main.cpp
Normal file
17
local/pkgs/ufo/src/main.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
# include <ufo/fold.hpp>
|
||||
# include <ufo/unfold.hpp>
|
||||
# include <ufo/plot.hpp>
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
if (argc != 3)
|
||||
throw std::runtime_error(fmt::format("Usage: {} task config.yaml", argv[0]));
|
||||
if (argv[1] == std::string("fold"))
|
||||
ufo::FoldSolver{argv[2]}();
|
||||
else if (argv[1] == std::string("unfold"))
|
||||
ufo::UnfoldSolver{argv[2]}();
|
||||
else if (argv[1] == std::string("plot"))
|
||||
ufo::PlotSolver{argv[2]}();
|
||||
else
|
||||
throw std::runtime_error(fmt::format("Unknown task: {}", argv[1]));
|
||||
}
|
||||
266
local/pkgs/ufo/src/plot.cpp
Normal file
266
local/pkgs/ufo/src/plot.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
# include <ufo/plot.hpp>
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
PlotSolver::InputType::UnfoldedDataType::UnfoldedDataType(std::string filename)
|
||||
{
|
||||
static_cast<UnfoldSolver::OutputType&>(*this) = zpp_read<UnfoldSolver::OutputType>(filename);
|
||||
}
|
||||
|
||||
PlotSolver::InputType::InputType(std::string config_file)
|
||||
{
|
||||
auto input = YAML::LoadFile(config_file);
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
for (unsigned j = 0; j < 3; j++)
|
||||
PrimativeCell(i, j) = input["PrimativeCell"][i][j].as<double>();
|
||||
for (auto& figure : input["Figures"].as<std::vector<YAML::Node>>())
|
||||
{
|
||||
Figures.emplace_back();
|
||||
auto qpoints = figure["Qpoints"]
|
||||
.as<std::vector<std::vector<std::vector<double>>>>();
|
||||
for (auto& line : qpoints)
|
||||
{
|
||||
Figures.back().Qpoints.emplace_back();
|
||||
for (auto& point : line)
|
||||
Figures.back().Qpoints.back().emplace_back(point.at(0), point.at(1), point.at(2));
|
||||
if (Figures.back().Qpoints.back().size() < 2)
|
||||
throw std::runtime_error("Not enough points in a line");
|
||||
}
|
||||
if (Figures.back().Qpoints.size() < 1)
|
||||
throw std::runtime_error("Not enough lines in a figure");
|
||||
Figures.back().Resolution = figure["Resolution"].as<std::pair<unsigned, unsigned>>();
|
||||
Figures.back().Range = figure["Range"].as<std::pair<double, double>>();
|
||||
Figures.back().PictureFile
|
||||
= DataFile(figure["PictureFile"], {"png"}, config_file);
|
||||
if (figure["YTicks"])
|
||||
Figures.back().YTicks = figure["YTicks"].as<std::vector<double>>();
|
||||
if (figure["DataFiles"])
|
||||
{
|
||||
Figures.back().DataFiles.emplace();
|
||||
for (auto& data_file : figure["DataFiles"].as<std::vector<YAML::Node>>())
|
||||
Figures.back().DataFiles->emplace_back()
|
||||
= DataFile(data_file, {"hdf5", "zpp"}, config_file);
|
||||
}
|
||||
}
|
||||
UnfoldedDataFile = DataFile(input["UnfoldedDataFile"], {"zpp"}, config_file);
|
||||
UnfoldedData = UnfoldedDataType(UnfoldedDataFile.Filename);
|
||||
}
|
||||
const PlotSolver::OutputType& PlotSolver::OutputType::write(std::string filename, std::string format) const
|
||||
{
|
||||
if (format == "zpp")
|
||||
zpp_write(*this, filename);
|
||||
else if (format == "hdf5")
|
||||
{
|
||||
std::vector resolution{ Resolution.first, Resolution.second };
|
||||
std::vector range{ Range.first, Range.second };
|
||||
Hdf5file{}.open_for_write(filename).write(Values, "Values")
|
||||
.write(XTicks, "XTicks")
|
||||
.write(YTicks, "YTicks")
|
||||
.write(resolution, "Resolution")
|
||||
.write(range, "Range");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
PlotSolver::PlotSolver(std::string config_file) : Input_(config_file) {}
|
||||
|
||||
PlotSolver& PlotSolver::operator()()
|
||||
{
|
||||
Output_.emplace();
|
||||
for (auto& figure : Input_.Figures)
|
||||
{
|
||||
// 外层表示不同的线段的端点,内层表示这个线段上的 q 点
|
||||
std::vector<std::vector<std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>>> qpoints;
|
||||
std::vector<std::pair<Eigen::Vector3d, Eigen::Vector3d>> lines;
|
||||
for (auto& path : figure.Qpoints)
|
||||
for (unsigned i = 0; i < path.size() - 1; i++)
|
||||
{
|
||||
lines.emplace_back(path[i], path[i + 1]);
|
||||
qpoints.push_back(search_qpoints
|
||||
(
|
||||
lines.back(), Input_.UnfoldedData.QpointData,
|
||||
0.001, i != path.size() - 2
|
||||
));
|
||||
}
|
||||
auto [values, x_ticks] = calculate_values
|
||||
(
|
||||
Input_.PrimativeCell, lines, qpoints, figure.Resolution, figure.Range
|
||||
);
|
||||
auto y_ticks = figure.YTicks.value_or(std::vector<double>{});
|
||||
for (auto& _ : y_ticks)
|
||||
_ = (_ - figure.Range.first) / (figure.Range.second - figure.Range.first) * figure.Resolution.second;
|
||||
plot(values, figure.PictureFile.Filename, x_ticks, y_ticks);
|
||||
Output_->emplace_back();
|
||||
Output_->back().Values = std::move(values);
|
||||
Output_->back().XTicks = std::move(x_ticks);
|
||||
Output_->back().YTicks = std::move(y_ticks);
|
||||
Output_->back().Resolution = figure.Resolution;
|
||||
Output_->back().Range = figure.Range;
|
||||
if (figure.DataFiles)
|
||||
for (auto& data_file : *figure.DataFiles)
|
||||
Output_->back().write(data_file.Filename, data_file.Format);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>> PlotSolver::search_qpoints
|
||||
(
|
||||
const std::pair<Eigen::Vector3d, Eigen::Vector3d>& path,
|
||||
const decltype(InputType::UnfoldedDataType::QpointData)& available_qpoints,
|
||||
double threshold, bool exclude_endpoint
|
||||
)
|
||||
{
|
||||
std::multimap<double, std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>> selected_qpoints;
|
||||
// 对于 output 中的每一个点, 检查这个点是否在路径上. 如果在, 把它加入到 selected_qpoints 中
|
||||
for (auto& qpoint : available_qpoints)
|
||||
{
|
||||
// 计算三点围成的三角形的面积的两倍
|
||||
auto area = (path.second - path.first).cross(qpoint.Qpoint - path.first).norm();
|
||||
// 计算这个点到前两个点所在直线的距离
|
||||
auto distance = area / (path.second - path.first).norm();
|
||||
// 如果这个点到前两个点所在直线的距离小于阈值, 则认为这个点在路径上
|
||||
if (distance < threshold)
|
||||
{
|
||||
// 计算这个点到前两个点的距离, 两个距离都应该小于两点之间的距离
|
||||
auto distance1 = (qpoint.Qpoint - path.first).norm();
|
||||
auto distance2 = (qpoint.Qpoint - path.second).norm();
|
||||
auto distance3 = (path.second - path.first).norm();
|
||||
if (distance1 < distance3 + threshold && distance2 < distance3 + threshold)
|
||||
// 如果这个点不在终点处, 或者不排除终点, 则加入
|
||||
if (distance2 > threshold || !exclude_endpoint)
|
||||
selected_qpoints.emplace(distance1, std::ref(qpoint));
|
||||
}
|
||||
}
|
||||
// 去除非常接近的点
|
||||
for (auto it = selected_qpoints.begin(); it != selected_qpoints.end();)
|
||||
{
|
||||
auto next = std::next(it);
|
||||
if (next == selected_qpoints.end())
|
||||
break;
|
||||
else if (next->first - it->first < threshold)
|
||||
selected_qpoints.erase(next);
|
||||
else
|
||||
it = next;
|
||||
}
|
||||
if (selected_qpoints.empty())
|
||||
throw std::runtime_error("No q points found");
|
||||
std::vector<std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>> result;
|
||||
for (auto& qpoint : selected_qpoints)
|
||||
result.push_back(qpoint.second);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::tuple<std::vector<std::vector<double>>, std::vector<double>> PlotSolver::calculate_values
|
||||
(
|
||||
const Eigen::Matrix3d primative_cell,
|
||||
const std::vector<std::pair<Eigen::Vector3d, Eigen::Vector3d>>& path,
|
||||
const std::vector<std::vector<std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>>>& qpoints,
|
||||
const decltype(InputType::FigureConfigType::Resolution)& resolution,
|
||||
const decltype(InputType::FigureConfigType::Range)& range
|
||||
)
|
||||
{
|
||||
// 整理输入
|
||||
std::map<double, std::reference_wrapper<const UnfoldSolver::OutputType::QpointDataType>> qpoints_with_distance;
|
||||
double total_distance = 0;
|
||||
std::vector<double> x_ticks;
|
||||
for (unsigned i = 0; i < path.size(); i++)
|
||||
{
|
||||
for (auto& _ : qpoints[i])
|
||||
qpoints_with_distance.emplace
|
||||
(
|
||||
total_distance
|
||||
+ ((_.get().Qpoint - path[i].first).transpose() * primative_cell.inverse().transpose()).norm(),
|
||||
_
|
||||
);
|
||||
total_distance += ((path[i].second - path[i].first).transpose() * primative_cell.inverse().transpose()).norm();
|
||||
if (i != path.size() - 1)
|
||||
x_ticks.push_back(total_distance);
|
||||
}
|
||||
for (auto& _ : x_ticks)
|
||||
_ = _ / total_distance * resolution.first;
|
||||
|
||||
// 插值
|
||||
std::vector<std::vector<double>> values;
|
||||
auto blend = []
|
||||
(
|
||||
const UnfoldSolver::OutputType::QpointDataType& a,
|
||||
const UnfoldSolver::OutputType::QpointDataType& b,
|
||||
double ratio, unsigned resolution, std::pair<double, double> range
|
||||
) -> std::vector<double>
|
||||
{
|
||||
// 计算插值结果
|
||||
std::vector<double> frequency, weight;
|
||||
for (unsigned i = 0; i < a.ModeData.size(); i++)
|
||||
{
|
||||
frequency.push_back(a.ModeData[i].Frequency * ratio + b.ModeData[i].Frequency * (1 - ratio));
|
||||
weight.push_back(a.ModeData[i].Weight * ratio + b.ModeData[i].Weight * (1 - ratio));
|
||||
}
|
||||
std::vector<double> result(resolution);
|
||||
for (unsigned i = 0; i < frequency.size(); i++)
|
||||
{
|
||||
int index = (frequency[i] - range.first) / (range.second - range.first) * resolution;
|
||||
if (index >= 0 && index < static_cast<int>(resolution))
|
||||
result[index] += weight[i];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
for (unsigned i = 0; i < resolution.first; i++)
|
||||
{
|
||||
auto current_distance = total_distance * i / resolution.first;
|
||||
auto it = qpoints_with_distance.lower_bound(current_distance);
|
||||
if (it == qpoints_with_distance.begin())
|
||||
values.push_back(blend(it->second.get(), it->second.get(), 1, resolution.second, range));
|
||||
else if (it == qpoints_with_distance.end())
|
||||
values.push_back(blend(std::prev(it)->second.get(), std::prev(it)->second.get(), 1, resolution.second,
|
||||
range));
|
||||
else
|
||||
values.push_back(blend
|
||||
(
|
||||
std::prev(it)->second.get(), it->second.get(),
|
||||
(it->first - current_distance) / (it->first - std::prev(it)->first),
|
||||
resolution.second, range)
|
||||
);
|
||||
}
|
||||
return {values, x_ticks};
|
||||
}
|
||||
void PlotSolver::plot
|
||||
(
|
||||
const std::vector<std::vector<double>>& values,
|
||||
const std::string& filename,
|
||||
const std::vector<double>& x_ticks, const std::vector<double>& y_ticks
|
||||
)
|
||||
{
|
||||
std::vector<std::vector<double>>
|
||||
r(values[0].size(), std::vector<double>(values.size(), 0)),
|
||||
g(values[0].size(), std::vector<double>(values.size(), 0)),
|
||||
b(values[0].size(), std::vector<double>(values.size(), 0)),
|
||||
a(values[0].size(), std::vector<double>(values.size(), 0));
|
||||
for (unsigned i = 0; i < values[0].size(); i++)
|
||||
for (unsigned j = 0; j < values.size(); j++)
|
||||
{
|
||||
auto v = values[j][i];
|
||||
if (v < 0.05)
|
||||
v = 0;
|
||||
a[i][j] = v * 100 * 255;
|
||||
if (a[i][j] > 255)
|
||||
a[i][j] = 255;
|
||||
r[i][j] = 255 - v * 2 * 255;
|
||||
if (r[i][j] < 0)
|
||||
r[i][j] = 0;
|
||||
g[i][j] = 255 - v * 2 * 255;
|
||||
if (g[i][j] < 0)
|
||||
g[i][j] = 0;
|
||||
b[i][j] = 255;
|
||||
}
|
||||
auto f = matplot::figure<matplot::backend::gnuplot>(true);
|
||||
auto ax = f->current_axes();
|
||||
auto image = ax->image(std::tie(r, g, b));
|
||||
image->matrix_a(a);
|
||||
ax->y_axis().reverse(false);
|
||||
ax->x_axis().tick_values(x_ticks);
|
||||
ax->x_axis().tick_length(1);
|
||||
ax->y_axis().tick_values(y_ticks);
|
||||
ax->y_axis().tick_length(1);
|
||||
f->save(filename, "png");
|
||||
}
|
||||
}
|
||||
47
local/pkgs/ufo/src/solver.cpp
Normal file
47
local/pkgs/ufo/src/solver.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
# include <ufo/solver.hpp>
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
concurrencpp::generator<std::pair<Eigen::Vector<unsigned, 3>, unsigned>> Solver::triplet_sequence
|
||||
(Eigen::Vector<unsigned, 3> range)
|
||||
{
|
||||
for (unsigned x = 0; x < range[0]; x++)
|
||||
for (unsigned y = 0; y < range[1]; y++)
|
||||
for (unsigned z = 0; z < range[2]; z++)
|
||||
co_yield
|
||||
{
|
||||
Eigen::Vector<unsigned, 3>{{x}, {y}, {z}},
|
||||
x * range[1] * range[2] + y * range[2] + z
|
||||
};
|
||||
}
|
||||
|
||||
Solver::DataFile::DataFile
|
||||
(YAML::Node node, std::set<std::string> supported_format, std::string config_file, bool allow_same_as_config_file)
|
||||
{
|
||||
if (auto _ = node["SameAsConfigFile"])
|
||||
{
|
||||
auto __ = _.as<bool>();
|
||||
if (__ && !allow_same_as_config_file)
|
||||
throw std::runtime_error("\"SameAsConfigFile: true\" is not allowed here.");
|
||||
ExtraParameters["SameAsConfigFile"] = __;
|
||||
if (__)
|
||||
{
|
||||
Filename = config_file;
|
||||
Format = "yaml";
|
||||
return;
|
||||
}
|
||||
}
|
||||
Filename = node["Filename"].as<std::string>();
|
||||
Format = node["Format"].as<std::string>();
|
||||
if (!supported_format.contains(Format))
|
||||
throw std::runtime_error(fmt::format("Unsupported format: \"{}\"", Format));
|
||||
if (auto _ = node["RelativeToConfigFile"])
|
||||
{
|
||||
auto __ = _.as<bool>();
|
||||
ExtraParameters["RelativeToConfigFile"] = __;
|
||||
if (__)
|
||||
Filename = std::filesystem::path(config_file).parent_path() / Filename;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
429
local/pkgs/ufo/src/unfold.cpp
Normal file
429
local/pkgs/ufo/src/unfold.cpp
Normal file
@@ -0,0 +1,429 @@
|
||||
# include <ufo/unfold.hpp>
|
||||
|
||||
namespace ufo
|
||||
{
|
||||
UnfoldSolver::InputType::InputType(std::string filename)
|
||||
{
|
||||
// read main input file
|
||||
{
|
||||
auto node = YAML::LoadFile(filename);
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
for (unsigned j = 0; j < 3; j++)
|
||||
PrimativeCell(i, j) = node["PrimativeCell"][i][j].as<double>();
|
||||
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
SuperCellMultiplier(i) = node["SuperCellMultiplier"][i].as<int>();
|
||||
|
||||
if (auto value = node["SuperCellDeformation"])
|
||||
{
|
||||
SuperCellDeformation.emplace();
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
for (unsigned j = 0; j < 3; j++)
|
||||
(*SuperCellDeformation)(i, j) = value[i][j].as<double>();
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < 3; i++)
|
||||
PrimativeCellBasisNumber(i) = node["PrimativeCellBasisNumber"][i].as<int>();
|
||||
|
||||
AtomPositionInputFile = DataFile
|
||||
(
|
||||
node["AtomPositionInputFile"], {"yaml"},
|
||||
filename, true
|
||||
);
|
||||
QpointDataInputFile = DataFile
|
||||
(
|
||||
node["QpointDataInputFile"], {"yaml", "hdf5"},
|
||||
filename, true
|
||||
);
|
||||
if (auto value = node["QpointDataOutputFile"])
|
||||
{
|
||||
QpointDataOutputFile.resize(value.size());
|
||||
for (unsigned i = 0; i < value.size(); i++)
|
||||
QpointDataOutputFile[i] = DataFile
|
||||
(
|
||||
value[i], {"yaml", "yaml-human-readable", "zpp", "hdf5"},
|
||||
filename, false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (AtomPositionInputFile.Format == "yaml")
|
||||
{
|
||||
auto node = YAML::LoadFile(AtomPositionInputFile.Filename);
|
||||
std::vector<YAML::Node> points;
|
||||
if (auto _ = node["points"])
|
||||
points = _.as<std::vector<YAML::Node>>();
|
||||
else
|
||||
points = node["unit_cell"]["points"].as<std::vector<YAML::Node>>();
|
||||
auto atom_position_to_super_cell = Eigen::MatrixX3d(points.size(), 3);
|
||||
for (unsigned i = 0; i < points.size(); i++)
|
||||
for (unsigned j = 0; j < 3; j++)
|
||||
atom_position_to_super_cell(i, j) = points[i]["coordinates"][j].as<double>();
|
||||
auto super_cell = (SuperCellDeformation.value_or(Eigen::Matrix3d::Identity())
|
||||
* SuperCellMultiplier.cast<double>().asDiagonal() * PrimativeCell).eval();
|
||||
AtomPosition = atom_position_to_super_cell * super_cell;
|
||||
}
|
||||
if (QpointDataInputFile.Format == "yaml")
|
||||
{
|
||||
auto node = YAML::LoadFile(QpointDataInputFile.Filename);
|
||||
auto phonon = node["phonon"].as<std::vector<YAML::Node>>();
|
||||
QpointData.resize(phonon.size());
|
||||
for (unsigned i = 0; i < phonon.size(); i++)
|
||||
{
|
||||
for (unsigned j = 0; j < 3; j++)
|
||||
QpointData[i].Qpoint(j) = phonon[i]["q-position"][j].as<double>();
|
||||
auto band = phonon[i]["band"].as<std::vector<YAML::Node>>();
|
||||
QpointData[i].ModeData.resize(band.size());
|
||||
for (unsigned j = 0; j < band.size(); j++)
|
||||
{
|
||||
QpointData[i].ModeData[j].Frequency = band[j]["frequency"].as<double>();
|
||||
auto eigenvector_vectors = band[j]["eigenvector"]
|
||||
.as<std::vector<std::vector<std::vector<double>>>>();
|
||||
Eigen::MatrixX3cd eigenvectors(AtomPosition.rows(), 3);
|
||||
for (unsigned k = 0; k < AtomPosition.rows(); k++)
|
||||
for (unsigned l = 0; l < 3; l++)
|
||||
eigenvectors(k, l)
|
||||
= eigenvector_vectors[k][l][0] + 1i * eigenvector_vectors[k][l][1];
|
||||
// 需要对读入的原子运动状态作相位转换, 使得它们与我们的约定一致(对超胞周期性重复)
|
||||
// 这里还要需要做归一化处理 (指将数据简单地作为向量处理的归一化)
|
||||
auto& AtomMovement = QpointData[i].ModeData[j].AtomMovement;
|
||||
// AtomMovement = eigenvectors.array().colwise() * (-2 * std::numbers::pi_v<double> * 1i
|
||||
// * (atom_position_to_super_cell * input.QpointData[i].Qpoint)).array().exp();
|
||||
// AtomMovement /= AtomMovement.norm();
|
||||
// phonopy 似乎已经进行了相位的转换!为什么?
|
||||
AtomMovement = eigenvectors / eigenvectors.norm();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (QpointDataInputFile.Format == "hdf5")
|
||||
{
|
||||
std::vector<std::vector<std::vector<double>>> frequency, path;
|
||||
std::vector<std::vector<std::vector<std::vector<PhonopyComplex>>>> eigenvector_vector;
|
||||
Hdf5file{}.open_for_read(QpointDataInputFile.Filename).read(frequency, "/frequency")
|
||||
.read(eigenvector_vector, "/eigenvector")
|
||||
.read(path, "/path");
|
||||
std::vector size = { frequency.size(), frequency[0].size(), frequency[0][0].size() };
|
||||
QpointData.resize(size[0] * size[1]);
|
||||
for (unsigned i = 0; i < size[0]; i++)
|
||||
for (unsigned j = 0; j < size[1]; j++)
|
||||
{
|
||||
QpointData[i * size[1] + j].Qpoint = Eigen::Vector3d(path[i][j].data());
|
||||
QpointData[i * size[1] + j].ModeData.resize(size[2]);
|
||||
for (unsigned k = 0; k < size[2]; k++)
|
||||
{
|
||||
QpointData[i * size[1] + j].ModeData[k].Frequency = frequency[i][j][k];
|
||||
Eigen::MatrixX3cd eigenvectors(AtomPosition.rows(), 3);
|
||||
for (unsigned l = 0; l < AtomPosition.rows(); l++)
|
||||
for (unsigned m = 0; m < 3; m++)
|
||||
eigenvectors(l, m)
|
||||
= eigenvector_vector[i][j][l * 3 + m][k].r + eigenvector_vector[i][j][l * 3 + m][k].i * 1i;
|
||||
QpointData[i * size[1] + j].ModeData[k].AtomMovement = eigenvectors / eigenvectors.norm();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnfoldSolver::OutputType::write
|
||||
(decltype(InputType::QpointDataOutputFile) output_files) const
|
||||
{
|
||||
for (auto& output_file : output_files)
|
||||
write(output_file.Filename, output_file.Format);
|
||||
}
|
||||
void UnfoldSolver::OutputType::write(std::string filename, std::string format, unsigned percision) const
|
||||
{
|
||||
if (format == "yaml")
|
||||
std::ofstream(filename) << [&]
|
||||
{
|
||||
std::stringstream print;
|
||||
print << "QpointData:\n";
|
||||
for (auto& qpoint: QpointData)
|
||||
{
|
||||
print << fmt::format(" - Qpoint: [ {1:.{0}f}, {2:.{0}f}, {3:.{0}f} ]\n",
|
||||
percision, qpoint.Qpoint[0], qpoint.Qpoint[1], qpoint.Qpoint[2]);
|
||||
print << fmt::format(" Source: [ {1:.{0}f}, {2:.{0}f}, {3:.{0}f} ]\n",
|
||||
percision, qpoint.Source[0], qpoint.Source[1], qpoint.Source[2]);
|
||||
print << " ModeData:\n";
|
||||
for (auto& mode: qpoint.ModeData)
|
||||
print << fmt::format(" - {{ Frequency: {1:.{0}f}, Weight: {2:.{0}f} }}\n",
|
||||
percision, mode.Frequency, mode.Weight);
|
||||
}
|
||||
return print.str();
|
||||
}();
|
||||
else if (format == "yaml-human-readable")
|
||||
{
|
||||
std::remove_cvref_t<decltype(*this)> output;
|
||||
std::map<unsigned, std::vector<decltype(QpointData)::const_iterator>>
|
||||
meta_qpoint_to_sub_qpoint_iterators;
|
||||
for (auto it = QpointData.begin(); it != QpointData.end(); it++)
|
||||
meta_qpoint_to_sub_qpoint_iterators[it->SourceIndex_].push_back(it);
|
||||
for (auto [meta_qpoint_index, sub_qpoint_iterators] : meta_qpoint_to_sub_qpoint_iterators)
|
||||
for (auto& qpoint : sub_qpoint_iterators)
|
||||
{
|
||||
std::map<double, double> frequency_to_weight;
|
||||
for (unsigned i_of_mode = 0; i_of_mode < qpoint->ModeData.size(); i_of_mode++)
|
||||
{
|
||||
auto frequency = qpoint->ModeData[i_of_mode].Frequency;
|
||||
auto weight = qpoint->ModeData[i_of_mode].Weight;
|
||||
auto it_lower = frequency_to_weight.lower_bound(frequency - 0.1);
|
||||
auto it_upper = frequency_to_weight.upper_bound(frequency + 0.1);
|
||||
if (it_lower == it_upper)
|
||||
frequency_to_weight[frequency] = weight;
|
||||
else
|
||||
{
|
||||
auto frequency_sum = std::accumulate(it_lower, it_upper, 0.,
|
||||
[](const auto& a, const auto& b) { return a + b.first * b.second; });
|
||||
auto weight_sum = std::accumulate(it_lower, it_upper, 0.,
|
||||
[](const auto& a, const auto& b) { return a + b.second; });
|
||||
frequency_sum += frequency * weight;
|
||||
weight_sum += weight;
|
||||
frequency_to_weight.erase(it_lower, it_upper);
|
||||
frequency_to_weight[frequency_sum / weight_sum] = weight_sum;
|
||||
}
|
||||
}
|
||||
auto& _ = output.QpointData.emplace_back();
|
||||
_.Qpoint = qpoint->Qpoint;
|
||||
_.Source = qpoint->Source;
|
||||
_.SourceIndex_ = qpoint->SourceIndex_;
|
||||
for (auto [frequency, weight] : frequency_to_weight)
|
||||
if (weight > 0.1)
|
||||
{
|
||||
auto& __ = _.ModeData.emplace_back();
|
||||
__.Frequency = frequency;
|
||||
__.Weight = weight;
|
||||
}
|
||||
}
|
||||
output.write(filename, "yaml", 3);
|
||||
}
|
||||
else if (format == "zpp")
|
||||
zpp_write(*this, filename);
|
||||
else if (format == "hdf5")
|
||||
{
|
||||
std::vector<std::vector<double>> Qpoint, Source, Frequency, Weight;
|
||||
for (auto& qpoint : QpointData)
|
||||
{
|
||||
Qpoint.emplace_back(qpoint.Qpoint.data(), qpoint.Qpoint.data() + 3);
|
||||
Source.emplace_back(qpoint.Source.data(), qpoint.Source.data() + 3);
|
||||
Frequency.emplace_back();
|
||||
Weight.emplace_back();
|
||||
for (auto& mode : qpoint.ModeData)
|
||||
{
|
||||
Frequency.back().push_back(mode.Frequency);
|
||||
Weight.back().push_back(mode.Weight);
|
||||
}
|
||||
}
|
||||
Hdf5file{}.open_for_write(filename).write(Qpoint, "/Qpoint")
|
||||
.write(Source, "/Source")
|
||||
.write(Frequency, "/Frequency")
|
||||
.write(Weight, "/Weight");
|
||||
}
|
||||
}
|
||||
|
||||
UnfoldSolver::UnfoldSolver(std::string config_file) : Input_([&]
|
||||
{
|
||||
std::clog << "Reading input file... " << std::flush;
|
||||
return config_file;
|
||||
}())
|
||||
{
|
||||
std::clog << "Done." << std::endl;
|
||||
}
|
||||
|
||||
UnfoldSolver& UnfoldSolver::operator()()
|
||||
{
|
||||
if (!Basis_)
|
||||
{
|
||||
std::clog << "Constructing basis... " << std::flush;
|
||||
Basis_ = construct_basis
|
||||
(
|
||||
Input_.PrimativeCell, Input_.SuperCellMultiplier,
|
||||
Input_.PrimativeCellBasisNumber, Input_.AtomPosition
|
||||
);
|
||||
std::clog << "Done." << std::endl;
|
||||
}
|
||||
if (!Output_)
|
||||
{
|
||||
std::clog << "Calculating projection coefficient... " << std::flush;
|
||||
std::vector<std::reference_wrapper<const decltype
|
||||
(InputType::QpointDataType::ModeDataType::AtomMovement)>> mode_data;
|
||||
for (auto& qpoint : Input_.QpointData)
|
||||
for (auto& mode : qpoint.ModeData)
|
||||
mode_data.emplace_back(mode.AtomMovement);
|
||||
std::atomic<unsigned> number_of_finished_modes(0);
|
||||
std::thread print_thread([&]
|
||||
{
|
||||
unsigned n;
|
||||
while ((n = number_of_finished_modes) < mode_data.size())
|
||||
{
|
||||
std::osyncstream(std::cerr) << fmt::format("\rCalculating projection coefficient... ({}/{})",
|
||||
number_of_finished_modes, mode_data.size()) << std::flush;
|
||||
std::this_thread::sleep_for(100ms);
|
||||
number_of_finished_modes.wait(n);
|
||||
}
|
||||
});
|
||||
auto projection_coefficient = construct_projection_coefficient
|
||||
(*Basis_, mode_data, number_of_finished_modes);
|
||||
number_of_finished_modes = mode_data.size();
|
||||
print_thread.join();
|
||||
std::clog << "\33[2K\rCalculating projection coefficient... Done." << std::endl;
|
||||
|
||||
std::clog << "Constructing output... " << std::flush;
|
||||
std::vector<std::reference_wrapper<const decltype(InputType::QpointDataType::Qpoint)>> qpoint;
|
||||
std::vector<std::vector<std::reference_wrapper<const
|
||||
decltype(InputType::QpointDataType::ModeDataType::Frequency)>>> frequency;
|
||||
for (auto& qpoint_data : Input_.QpointData)
|
||||
{
|
||||
qpoint.emplace_back(qpoint_data.Qpoint);
|
||||
frequency.emplace_back();
|
||||
for (auto& mode_data : qpoint_data.ModeData)
|
||||
frequency.back().emplace_back(mode_data.Frequency);
|
||||
}
|
||||
Output_ = construct_output
|
||||
(
|
||||
Input_.SuperCellMultiplier,
|
||||
Input_.SuperCellDeformation, qpoint, frequency, projection_coefficient
|
||||
);
|
||||
std::clog << "Done." << std::endl;
|
||||
}
|
||||
std::clog << "Writing output... " << std::flush;
|
||||
Output_->write(Input_.QpointDataOutputFile);
|
||||
std::clog << "Done." << std::endl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UnfoldSolver::BasisType UnfoldSolver::construct_basis
|
||||
(
|
||||
const decltype(InputType::PrimativeCell)& primative_cell,
|
||||
const decltype(InputType::SuperCellMultiplier)& super_cell_multiplier,
|
||||
const decltype(InputType::PrimativeCellBasisNumber)& primative_cell_basis_number,
|
||||
const decltype(InputType::AtomPosition)& atom_position
|
||||
)
|
||||
{
|
||||
BasisType basis(super_cell_multiplier.prod());
|
||||
// 每个 q 点对应的一组 sub qpoint。不同的 q 点所对应的 sub qpoint 是不一样的,但 sub qpoint 与 q 点的相对位置一致。
|
||||
// 这里 xyz_of_diff_of_sub_qpoint 即表示这个相对位置,单位为超胞的倒格矢
|
||||
for (auto [xyz_of_diff_of_sub_qpoint_by_reciprocal_modified_super_cell, i_of_sub_qpoint]
|
||||
: triplet_sequence(super_cell_multiplier))
|
||||
{
|
||||
basis[i_of_sub_qpoint].resize(primative_cell_basis_number.prod());
|
||||
for (auto [xyz_of_basis, i_of_basis] : triplet_sequence(primative_cell_basis_number))
|
||||
{
|
||||
// 计算 q 点的坐标, 单位为单胞的倒格矢
|
||||
auto diff_of_sub_qpoint_by_reciprocal_primative_cell = xyz_of_basis.cast<double>()
|
||||
+ super_cell_multiplier.cast<double>().cwiseInverse().asDiagonal()
|
||||
* xyz_of_diff_of_sub_qpoint_by_reciprocal_modified_super_cell.cast<double>();
|
||||
// 将 q 点坐标转换为埃^-1
|
||||
auto qpoint = (diff_of_sub_qpoint_by_reciprocal_primative_cell.transpose()
|
||||
* (primative_cell.transpose().inverse())).transpose();
|
||||
// 计算基矢
|
||||
basis[i_of_sub_qpoint][i_of_basis]
|
||||
= (2i * std::numbers::pi_v<double> * (atom_position * qpoint)).array().exp();
|
||||
}
|
||||
}
|
||||
return basis;
|
||||
}
|
||||
|
||||
std::vector<std::vector<double>> UnfoldSolver::construct_projection_coefficient
|
||||
(
|
||||
const BasisType& basis,
|
||||
const std::vector<std::reference_wrapper<const decltype
|
||||
(InputType::QpointDataType::ModeDataType::AtomMovement)>>& mode_data,
|
||||
std::atomic<unsigned>& number_of_finished_modes
|
||||
)
|
||||
{
|
||||
// 第一层下标对应不同模式, 第二层下标对应这个模式在反折叠后的 q 点(sub qpoint)
|
||||
std::vector<std::vector<double>> projection_coefficient(mode_data.size());
|
||||
// 对每个模式并行
|
||||
std::transform
|
||||
(
|
||||
std::execution::par, mode_data.begin(), mode_data.end(),
|
||||
projection_coefficient.begin(), [&](const auto& mode_data)
|
||||
{
|
||||
// 这里, mode_data 和 projection_coefficient 均指对应于一个模式的数据
|
||||
std::vector<double> projection_coefficient(basis.size());
|
||||
for (unsigned i_of_sub_qpoint = 0; i_of_sub_qpoint < basis.size(); i_of_sub_qpoint++)
|
||||
// 对于 basis 中, 对应于单胞倒格子的部分, 以及对应于不同方向的部分, 分别求内积, 然后求模方和
|
||||
for (unsigned i_of_basis = 0; i_of_basis < basis[i_of_sub_qpoint].size(); i_of_basis++)
|
||||
projection_coefficient[i_of_sub_qpoint] +=
|
||||
(basis[i_of_sub_qpoint][i_of_basis].transpose().conjugate() * mode_data.get())
|
||||
.array().abs2().sum();
|
||||
// 如果是严格地将向量分解到一组完备的基矢上, 那么不需要对计算得到的权重再做归一化处理
|
||||
// 但这里并不是这样一个严格的概念. 因此对分解到各个 sub qpoint 上的权重做归一化处理
|
||||
auto sum = std::accumulate
|
||||
(projection_coefficient.begin(), projection_coefficient.end(), 0.);
|
||||
for (auto& _ : projection_coefficient)
|
||||
_ /= sum;
|
||||
number_of_finished_modes++;
|
||||
return projection_coefficient;
|
||||
}
|
||||
);
|
||||
return projection_coefficient;
|
||||
}
|
||||
|
||||
UnfoldSolver::OutputType UnfoldSolver::construct_output
|
||||
(
|
||||
const decltype(InputType::SuperCellMultiplier)& super_cell_multiplier,
|
||||
const decltype(InputType::SuperCellDeformation)& super_cell_deformation,
|
||||
const std::vector<std::reference_wrapper<const decltype
|
||||
(InputType::QpointDataType::Qpoint)>>& meta_qpoint_by_reciprocal_super_cell,
|
||||
const std::vector<std::vector<std::reference_wrapper<const decltype
|
||||
(InputType::QpointDataType::ModeDataType::Frequency)>>>& frequency,
|
||||
const ProjectionCoefficientType_& projection_coefficient
|
||||
)
|
||||
{
|
||||
OutputType output;
|
||||
for
|
||||
(
|
||||
unsigned i_of_meta_qpoint = 0, num_of_mode_manipulated = 0;
|
||||
i_of_meta_qpoint < meta_qpoint_by_reciprocal_super_cell.size();
|
||||
i_of_meta_qpoint++
|
||||
)
|
||||
{
|
||||
for (auto [xyz_of_diff_of_sub_qpoint_by_reciprocal_modified_super_cell, i_of_sub_qpoint]
|
||||
: triplet_sequence(super_cell_multiplier))
|
||||
{
|
||||
auto& _ = output.QpointData.emplace_back();
|
||||
/*
|
||||
SubQpointByReciprocalModifiedSuperCell = XyzOfDiffOfSubQpointByReciprocalModifiedSuperCell +
|
||||
MetaQpointByReciprocalModifiedSuperCell;
|
||||
SubQpoint = SubQpointByReciprocalModifiedSuperCell.transpose() * ReciprocalModifiedSuperCell;
|
||||
SubQpoint = SubQpointByReciprocalPrimativeCell.transpose() * ReciprocalPrimativeCell;
|
||||
ReciprocalModifiedSuperCell = ModifiedSuperCell.inverse().transpose();
|
||||
ReciprocalPrimativeCell = PrimativeCell.inverse().transpose();
|
||||
ModifiedSuperCell = SuperCellMultiplier.asDiagonal() * PrimativeCell;
|
||||
MetaQpoint = MetaQpointByReciprocalModifiedSuperCell.transpose() * ReciprocalModifiedSuperCell;
|
||||
MetaQpoint = MetaQpointByReciprocalSuperCell.transpose() * ReciprocalSuperCell;
|
||||
ReciprocalSuperCell = SuperCell.inverse().transpose();
|
||||
ModifiedSuperCell = SuperCellDeformation * SuperCell;
|
||||
SuperCell = SuperCellMultiplier.asDiagonal() * PrimativeCell;
|
||||
整理可以得到:
|
||||
SubQpointByReciprocalPrimativeCell = SuperCellMultiplier.asDiagonal().inverse() *
|
||||
(XyzOfDiffOfSubQpointByReciprocalModifiedSuperCell +
|
||||
SuperCellDeformation.inverse() * MetaQpointByReciprocalSuperCell);
|
||||
但注意到, 这样得到的 SubQpoint 可能不在 ReciprocalPrimativeCell 中
|
||||
(当 SuperCellDeformation 不是单位矩阵时, 边界附近的一两条 SubQpoint 会出现这种情况).
|
||||
解决办法是, 在赋值时, 仅取 SubQpointByReciprocalPrimativeCell 的小数部分.
|
||||
*/
|
||||
auto sub_qpoint_by_reciprocal_primative_cell =
|
||||
(
|
||||
super_cell_multiplier.cast<double>().cwiseInverse().asDiagonal()
|
||||
* (
|
||||
xyz_of_diff_of_sub_qpoint_by_reciprocal_modified_super_cell.cast<double>()
|
||||
+ super_cell_deformation.value_or(Eigen::Matrix3d::Identity()).inverse()
|
||||
* meta_qpoint_by_reciprocal_super_cell[i_of_meta_qpoint].get().cast<double>()
|
||||
)
|
||||
).eval();
|
||||
_.Qpoint = sub_qpoint_by_reciprocal_primative_cell.array()
|
||||
- sub_qpoint_by_reciprocal_primative_cell.array().floor();
|
||||
_.Source = meta_qpoint_by_reciprocal_super_cell[i_of_meta_qpoint];
|
||||
_.SourceIndex_ = i_of_meta_qpoint;
|
||||
for (unsigned i_of_mode = 0; i_of_mode < frequency[i_of_meta_qpoint].size(); i_of_mode++)
|
||||
{
|
||||
auto& __ = _.ModeData.emplace_back();
|
||||
__.Frequency = frequency[i_of_meta_qpoint][i_of_mode];
|
||||
__.Weight = projection_coefficient[num_of_mode_manipulated + i_of_mode][i_of_sub_qpoint];
|
||||
}
|
||||
}
|
||||
num_of_mode_manipulated += frequency[i_of_meta_qpoint].size();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ let vasp = stdenvNoCC.mkDerivation
|
||||
for i in std gam ncl; do
|
||||
cp bin/vasp_$i $out/bin/vasp-$i
|
||||
done
|
||||
ln -s ${src} $out/src
|
||||
'';
|
||||
};
|
||||
in writeShellApplication
|
||||
|
||||
@@ -41,6 +41,9 @@ let
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
for i in std gam ncl; do cp bin/vasp_$i $out/bin/vasp-$i; done
|
||||
mkdir $out/src
|
||||
ln -s ${src} $out/src/vasp
|
||||
ln -s ${vtst} $out/src/vtst
|
||||
'';
|
||||
dontFixup = true;
|
||||
requiredSystemFeatures = [ "gccarch-exact-${stdenvNoCC.hostPlatform.gcc.arch}" ];
|
||||
|
||||
@@ -44,6 +44,9 @@ let
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
for i in std gam ncl; do cp bin/vasp_$i $out/bin/vasp-$i; done
|
||||
mkdir $out/src
|
||||
ln -s ${src} $out/src/vasp
|
||||
ln -s ${vtst} $out/src/vtst
|
||||
'';
|
||||
dontFixup = true;
|
||||
requiredSystemFeatures = [ "gccarch-exact-${stdenvNoCC.hostPlatform.gcc.arch}" ];
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
lib, stdenv, fetchurl, autoPatchelfHook, wrapGAppsHook, makeWrapper,
|
||||
glib, gtk2, xorg, libGLU, gtk3, writeShellScript, gsettings-desktop-schemas, xdg-utils
|
||||
glib, gtk2, xorg, libGLU, gtk3, writeShellScript, gsettings-desktop-schemas, xdg-utils, webkitgtk, jdk
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation rec
|
||||
{
|
||||
pname = "vesta";
|
||||
version = "3.5.5";
|
||||
version = "3.90.0a";
|
||||
src = fetchurl
|
||||
{
|
||||
url = "https://jp-minerals.org/vesta/archives/${version}/VESTA-gtk3.tar.bz2";
|
||||
sha256 = "sRzQNJA7+hsjLWmykqe6bH0p1/aGEB8hCuxCyPzxYHs=";
|
||||
url = "https://jp-minerals.org/vesta/archives/testing/VESTA-gtk3-x86_64.tar.bz2";
|
||||
sha256 = "0bsvfr3409g2v1wgnfixpkjz1yzl2j1nlrk5a5rkdfs94rrvxzaa";
|
||||
};
|
||||
desktopFile = fetchurl
|
||||
{
|
||||
@@ -18,8 +18,8 @@ stdenv.mkDerivation rec
|
||||
sha256 = "Tq4AzQgde2KIWKA1k6JlxvdphGG9JluHMZjVw0fBUeQ=";
|
||||
};
|
||||
|
||||
nativeBuildInputs = [ autoPatchelfHook wrapGAppsHook makeWrapper ];
|
||||
buildInputs = [ glib gtk2 xorg.libXxf86vm libGLU gtk3 xorg.libXtst ];
|
||||
nativeBuildInputs =
|
||||
[ autoPatchelfHook wrapGAppsHook makeWrapper glib gtk2 xorg.libXxf86vm libGLU gtk3 xorg.libXtst webkitgtk jdk ];
|
||||
|
||||
unpackPhase = "tar -xf ${src}";
|
||||
|
||||
@@ -32,11 +32,13 @@ stdenv.mkDerivation rec
|
||||
sed -i "s|Icon=.*|Icon=$out/opt/VESTA-gtk3/img/logo.png|" $out/share/applications/vesta.desktop
|
||||
|
||||
mkdir -p $out/opt
|
||||
cp -r VESTA-gtk3 $out/opt/VESTA-gtk3
|
||||
cp -r VESTA-gtk3-x86_64 $out/opt/VESTA-gtk3-x86_64
|
||||
|
||||
mkdir -p $out/bin
|
||||
makeWrapper $out/opt/VESTA-gtk3/VESTA $out/bin/vesta
|
||||
makeWrapper $out/opt/VESTA-gtk3-x86_64/VESTA $out/bin/vesta
|
||||
|
||||
patchelf --remove-needed libjawt.so $out/opt/VESTA-gtk3/PowderPlot/libswt-awt-gtk-3346.so
|
||||
patchelf --remove-needed libjawt.so $out/opt/VESTA-gtk3-x86_64/PowderPlot/libswt-awt-gtk-3346.so
|
||||
|
||||
ln -s ${src} $out/src
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -11,47 +11,6 @@ inputs:
|
||||
SuspendState=freeze
|
||||
HibernateMode=shutdown
|
||||
'';
|
||||
# reload iwlwifi after resume from hibernate
|
||||
hibernate-iwlwifi =
|
||||
{
|
||||
systemd.services.reload-iwlwifi-after-hibernate =
|
||||
{
|
||||
description = "reload iwlwifi after resume from hibernate";
|
||||
after = [ "systemd-hibernate.service" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
script = let modprobe = "${inputs.pkgs.kmod}/bin/modprobe"; in
|
||||
''
|
||||
${modprobe} -r iwlwifi
|
||||
${modprobe} iwlwifi
|
||||
echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
|
||||
'';
|
||||
wantedBy = [ "systemd-hibernate.service" ];
|
||||
};
|
||||
nixos.system.kernel.modules.modprobeConfig =
|
||||
[ "options iwlmvm power_scheme=1" "options iwlwifi uapsd_disable=1" ];
|
||||
};
|
||||
# disable wakeup on lid open
|
||||
suspend-lid-no-wakeup.systemd.services.lid-no-wakeup =
|
||||
{
|
||||
description = "lid no wake up";
|
||||
serviceConfig.Type = "oneshot";
|
||||
script =
|
||||
let
|
||||
cat = "${inputs.pkgs.coreutils}/bin/cat";
|
||||
grep = "${inputs.pkgs.gnugrep}/bin/grep";
|
||||
in
|
||||
''
|
||||
if ${cat} /proc/acpi/wakeup | ${grep} LID0 | ${grep} -q enabled
|
||||
then
|
||||
echo LID0 > /proc/acpi/wakeup
|
||||
fi
|
||||
if ${cat} /proc/acpi/wakeup | ${grep} XHCI | ${grep} -q enabled
|
||||
then
|
||||
echo XHCI > /proc/acpi/wakeup
|
||||
fi
|
||||
'';
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
# xmunet use old encryption
|
||||
xmunet.nixpkgs.config.packageOverrides = pkgs: { wpa_supplicant = pkgs.wpa_supplicant.overrideAttrs
|
||||
(attrs: { patches = attrs.patches ++ [ ./xmunet.patch ];}); };
|
||||
@@ -77,21 +36,10 @@ inputs:
|
||||
script = "${systemctl} start waydroid-container";
|
||||
};
|
||||
};
|
||||
firefox.programs.firefox.enable = inputs.lib.mkForce false;
|
||||
power.boot.kernelParams = [ "cpufreq.default_governor=powersave" ];
|
||||
backlight.boot.kernelParams = [ "nvidia.NVreg_RegistryDwords=EnableBrightnessControl=1" ];
|
||||
amdpstate.boot.kernelParams = [ "amd_pstate=active" ];
|
||||
wireplumber.environment.etc."wireplumber/main.lua.d/50-alsa-config.lua".text =
|
||||
let
|
||||
content = builtins.readFile
|
||||
(inputs.pkgs.wireplumber + "/share/wireplumber/main.lua.d/50-alsa-config.lua");
|
||||
matched = builtins.match
|
||||
".*\n([[:space:]]*)(--\\[\"session\\.suspend-timeout-seconds\"][^\n]*)[\n].*" content;
|
||||
spaces = builtins.elemAt matched 0;
|
||||
comment = builtins.elemAt matched 1;
|
||||
config = ''["session.suspend-timeout-seconds"] = 0'';
|
||||
in
|
||||
builtins.replaceStrings [(spaces + comment)] [(spaces + config)] content;
|
||||
hibernate-mt7921e.powerManagement.resumeCommands =
|
||||
let modprobe = "${inputs.pkgs.kmod}/bin/modprobe"; in "${modprobe} -r -w 3000 mt7921e && ${modprobe} mt7921e";
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ inputs:
|
||||
topInputs.impermanence.nixosModules.impermanence
|
||||
topInputs.nix-flatpak.nixosModules.nix-flatpak
|
||||
topInputs.chaotic.nixosModules.default
|
||||
{ config.chaotic.nyx.overlay.onTopOf = "user-pkgs"; }
|
||||
topInputs.catppuccin.nixosModules.catppuccin
|
||||
(inputs:
|
||||
{
|
||||
|
||||
@@ -50,9 +50,10 @@ inputs:
|
||||
{
|
||||
hardware.cpu = builtins.listToAttrs
|
||||
(map (name: { inherit name; value = { updateMicrocode = true; }; }) hardware.cpus);
|
||||
boot.initrd.availableKernelModules =
|
||||
let
|
||||
modules =
|
||||
boot =
|
||||
{
|
||||
initrd.availableKernelModules =
|
||||
let modules =
|
||||
{
|
||||
intel =
|
||||
[
|
||||
@@ -60,8 +61,11 @@ inputs:
|
||||
];
|
||||
amd = [];
|
||||
};
|
||||
in
|
||||
builtins.concatLists (map (cpu: modules.${cpu}) hardware.cpus);
|
||||
in builtins.concatLists (map (cpu: modules.${cpu}) hardware.cpus);
|
||||
kernelParams =
|
||||
let params = { intel = [ "intel_iommu=off" ]; amd = [ "amd_iommu=fullflush" ]; };
|
||||
in builtins.concatLists (map (cpu: params.${cpu}) hardware.cpus);
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
|
||||
@@ -13,11 +13,15 @@ inputs:
|
||||
]);
|
||||
default = null;
|
||||
};
|
||||
dynamicBoost = mkOption { type = types.bool; default = false; };
|
||||
prime =
|
||||
nvidia =
|
||||
{
|
||||
mode = mkOption { type = types.enum [ "offload" "sync" ]; default = "offload"; };
|
||||
busId = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
|
||||
dynamicBoost = mkOption { type = types.bool; default = false; };
|
||||
prime =
|
||||
{
|
||||
mode = mkOption { type = types.enum [ "offload" "sync" ]; default = "offload"; };
|
||||
busId = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
|
||||
};
|
||||
driver = mkOption { type = types.enum [ "production" "beta" ]; default = "production"; };
|
||||
};
|
||||
};
|
||||
config = let inherit (inputs.config.nixos.hardware) gpu; in inputs.lib.mkIf (gpu.type != null) (inputs.lib.mkMerge
|
||||
@@ -57,17 +61,21 @@ inputs:
|
||||
{
|
||||
modesetting.enable = true;
|
||||
powerManagement.enable = true;
|
||||
dynamicBoost.enable = inputs.lib.mkIf gpu.dynamicBoost true;
|
||||
dynamicBoost.enable = inputs.lib.mkIf gpu.nvidia.dynamicBoost true;
|
||||
nvidiaSettings = true;
|
||||
forceFullCompositionPipeline = true;
|
||||
# package = inputs.config.boot.kernelPackages.nvidiaPackages.production;
|
||||
package =
|
||||
let actualDriver = { production = "legacy_535"; }.${gpu.nvidia.driver} or gpu.nvidia.driver;
|
||||
in inputs.config.boot.kernelPackages.nvidiaPackages.${actualDriver};
|
||||
prime.allowExternalGpu = true;
|
||||
# nvidia 555 package have some bug, should use open
|
||||
open = inputs.lib.mkIf (gpu.nvidia.driver == "beta") true;
|
||||
};
|
||||
};
|
||||
boot =
|
||||
{
|
||||
kernelParams = inputs.lib.mkIf (builtins.elem "amd" gpus)
|
||||
[ "radeon.cik_support=0" "amdgpu.cik_support=1" "radeon.si_support=0" "amdgpu.si_support=1" "iommu=pt" ];
|
||||
[ "radeon.cik_support=0" "amdgpu.cik_support=1" "radeon.si_support=0" "amdgpu.si_support=1" ];
|
||||
blacklistedKernelModules = [ "nouveau" ];
|
||||
};
|
||||
environment.variables.VDPAU_DRIVER = inputs.lib.mkIf (builtins.elem "intel" gpus) "va_gl";
|
||||
@@ -82,13 +90,13 @@ inputs:
|
||||
{
|
||||
prime =
|
||||
{
|
||||
offload = inputs.lib.mkIf (gpu.prime.mode == "offload") { enable = true; enableOffloadCmd = true; };
|
||||
sync = inputs.lib.mkIf (gpu.prime.mode == "sync") { enable = true; };
|
||||
offload = inputs.lib.mkIf (gpu.nvidia.prime.mode == "offload") { enable = true; enableOffloadCmd = true; };
|
||||
sync = inputs.lib.mkIf (gpu.nvidia.prime.mode == "sync") { enable = true; };
|
||||
}
|
||||
// builtins.listToAttrs (builtins.map
|
||||
(gpu: { name = "${if gpu.name == "amd" then "amdgpu" else gpu.name}BusId"; value = "PCI:${gpu.value}"; })
|
||||
(inputs.localLib.attrsToList gpu.prime.busId));
|
||||
powerManagement.finegrained = inputs.lib.mkIf (gpu.prime.mode == "offload") true;
|
||||
(inputs.localLib.attrsToList gpu.nvidia.prime.busId));
|
||||
powerManagement.finegrained = inputs.lib.mkIf (gpu.nvidia.prime.mode == "offload") true;
|
||||
};}
|
||||
)
|
||||
]);
|
||||
|
||||
@@ -9,7 +9,8 @@ inputs:
|
||||
_packages =
|
||||
[
|
||||
# system management
|
||||
btrfs-assistant snapper-gui kdePackages.qtstyleplugin-kvantum ventoy-full cpu-x # etcher
|
||||
btrfs-assistant snapper-gui kdePackages.qtstyleplugin-kvantum ventoy-full cpu-x
|
||||
inputs.pkgs."pkgs-23.11".etcher
|
||||
# password and key management
|
||||
yubikey-manager yubikey-manager-qt yubikey-personalization yubikey-personalization-gui bitwarden
|
||||
# download
|
||||
|
||||
@@ -26,14 +26,18 @@ inputs:
|
||||
# media
|
||||
mpv nomacs
|
||||
# themes
|
||||
tela-circle-icon-theme localPackages.win11os-kde localPackages.fluent-kde localPackages.blurred-wallpaper
|
||||
localPackages.slate utterly-nord-plasma
|
||||
localPackages.win11os-kde localPackages.fluent-kde localPackages.blurred-wallpaper
|
||||
localPackages.slate utterly-nord-plasma utterly-round-plasma-style catppuccin catppuccin-sddm
|
||||
catppuccin-cursors catppuccinifier-gui catppuccinifier-cli catppuccin-plymouth
|
||||
(catppuccin-kde.override { flavour = [ "latte" ]; })
|
||||
(catppuccin-gtk.override { variant = "latte"; })
|
||||
(tela-circle-icon-theme.override { allColorVariants = true; })
|
||||
# terminal
|
||||
warp-terminal
|
||||
# development
|
||||
adb-sync
|
||||
# virtual keyboard
|
||||
# localPackages.kylin-virtual-keyboard
|
||||
# desktop sharing
|
||||
rustdesk-flutter
|
||||
];
|
||||
};
|
||||
programs =
|
||||
@@ -42,14 +46,27 @@ inputs:
|
||||
wireshark = { enable = true; package = inputs.pkgs.wireshark; };
|
||||
yubikey-touch-detector.enable = true;
|
||||
};
|
||||
nixpkgs.config.packageOverrides = pkgs:
|
||||
nixpkgs.overlays = [(final: prev:
|
||||
{
|
||||
telegram-desktop = pkgs.telegram-desktop.overrideAttrs (attrs:
|
||||
telegram-desktop = prev.telegram-desktop.overrideAttrs (attrs:
|
||||
{
|
||||
patches = (if (attrs ? patches) then attrs.patches else []) ++ [ ./telegram.patch ];
|
||||
});
|
||||
};
|
||||
kdePackages = prev.kdePackages.overrideScope (final: prev:
|
||||
{
|
||||
kwin = prev.kwin.overrideAttrs (prev: { patches = prev.patches ++
|
||||
[
|
||||
{
|
||||
"6.0.5" = inputs.pkgs.fetchurl
|
||||
{
|
||||
url = "https://aur.archlinux.org/cgit/aur.git/plain/explicit-sync.patch?h=kwin-explicit-sync"
|
||||
+ "&id=b6fb7e1b8651365af426cfc7be0d03b9615fdd3a";
|
||||
sha256 = "1zcksalmkf0mifmv0zl5awy1ch3fvfkkknxqk4mqg0vk1bbpjh2b";
|
||||
};
|
||||
}.${prev.version}
|
||||
]; });
|
||||
});
|
||||
})];
|
||||
services.pcscd.enable = true;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,7 @@ inputs:
|
||||
])];
|
||||
};
|
||||
};
|
||||
programs =
|
||||
{
|
||||
yazi.enable = true;
|
||||
mosh.enable = true;
|
||||
};
|
||||
programs.yazi.enable = true;
|
||||
services.fwupd.enable = true;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ inputs:
|
||||
[
|
||||
# basic tools
|
||||
beep dos2unix gnugrep pv tmux screen parallel tldr cowsay jq zellij ipfetch localPackages.pslist
|
||||
fastfetch reptyr
|
||||
fastfetch reptyr nushellFull duc ncdu progress
|
||||
# lsxx
|
||||
pciutils usbutils lshw util-linux lsof dmidecode
|
||||
pciutils usbutils lshw util-linux lsof dmidecode lm_sensors
|
||||
# top
|
||||
iotop iftop htop btop powertop s-tui
|
||||
# editor
|
||||
@@ -43,6 +43,7 @@ inputs:
|
||||
command-not-found.enable = false;
|
||||
autojump.enable = true;
|
||||
direnv = { enable = true; nix-direnv.enable = true; };
|
||||
mosh.enable = true;
|
||||
};
|
||||
services.udev.packages = with inputs.pkgs; [ yubikey-personalization libfido2 ];
|
||||
home-manager = { useGlobalPkgs = true; useUserPackages = true; };
|
||||
|
||||
137
modules/packages/ssh.nix
Normal file
137
modules/packages/ssh.nix
Normal file
@@ -0,0 +1,137 @@
|
||||
inputs:
|
||||
{
|
||||
config = inputs.lib.mkIf (builtins.elem "server" inputs.config.nixos.packages._packageSets)
|
||||
{
|
||||
services.openssh.knownHosts =
|
||||
let servers =
|
||||
{
|
||||
vps6 =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIO5ZcvyRyOnUCuRtqrM/Qf+AdUe3a5bhbnfyhw2FSLDZ";
|
||||
hostnames = [ "vps6.chn.moe" "wireguard.vps6.chn.moe" "74.211.99.69" "192.168.83.1" ];
|
||||
};
|
||||
"initrd.vps6" =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIB4DKB/zzUYco5ap6k9+UxeO04LL12eGvkmQstnYxgnS";
|
||||
hostnames = [ "initrd.vps6.chn.moe" "74.211.99.69" ];
|
||||
};
|
||||
vps7 =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIF5XkdilejDAlg5hZZD0oq69k8fQpe9hIJylTo/aLRgY";
|
||||
hostnames = [ "vps7.chn.moe" "wireguard.vps7.chn.moe" "ssh.git.chn.moe" "95.111.228.40" "192.168.83.2" ];
|
||||
};
|
||||
"initrd.vps7" =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIGZyQpdQmEZw3nLERFmk2tS1gpSvXwW0Eish9UfhrRxC";
|
||||
hostnames = [ "initrd.vps7.chn.moe" "95.111.228.40" ];
|
||||
};
|
||||
nas =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIIktNbEcDMKlibXg54u7QOLt0755qB/P4vfjwca8xY6V";
|
||||
hostnames = [ "wireguard.nas.chn.moe" "[office.chn.moe]:5440" "192.168.1.185" "192.168.83.4" ];
|
||||
};
|
||||
"initrd.nas" =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIAoMu0HEaFQsnlJL0L6isnkNZdRq0OiDXyaX3+fl3NjT";
|
||||
hostnames = [ "initrd.nas.chn.moe" "[office.chn.moe]:5440" "192.168.1.185" ];
|
||||
};
|
||||
surface =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIFdm3DcfHdcLP0oSpVrWwIZ/b9lZuakBSPwCFz2BdTJ7";
|
||||
hostnames = [ "192.168.1.166" "wireguard.surface.chn.moe" "192.168.83.5" ];
|
||||
};
|
||||
pc =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIMSfREi19OSwQnhdsE8wiNwGSFFJwNGN0M5gN+sdrrLJ";
|
||||
hostnames = [ "wireguard.pc.chn.moe" "[office.chn.moe]:3673" "192.168.1.105" "192.168.83.3" ];
|
||||
};
|
||||
hpc =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIDVpsQW3kZt5alHC6mZhay3ZEe2fRGziG4YJWCv2nn/O";
|
||||
hostnames = [ "hpc.xmu.edu.cn" ];
|
||||
};
|
||||
github =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl";
|
||||
hostnames = [ "github.com" ];
|
||||
};
|
||||
xmupc1 =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAINTvfywkKRwMrVp73HfHTfjhac2Tn9qX/lRjLr09ycHp";
|
||||
hostnames = [ "[office.chn.moe]:6007" "[xmupc1.chn.moe]:6007" "wireguard.xmupc1.chn.moe" "192.168.83.6" ];
|
||||
};
|
||||
xmupc2 =
|
||||
{
|
||||
ed25519 = "AAAAC3NzaC1lZDI1NTE5AAAAIJZ/+divGnDr0x+UlknA84Tfu6TPD+zBGmxWZY4Z38P6";
|
||||
hostnames = [ "[xmupc2.chn.moe]:6394" "wireguard.xmupc2.chn.moe" "192.168.83.7" ];
|
||||
};
|
||||
};
|
||||
in builtins.listToAttrs (builtins.map
|
||||
(server:
|
||||
{
|
||||
inherit (server) name;
|
||||
value =
|
||||
{
|
||||
publicKey = "ssh-ed25519 ${server.value.ed25519}";
|
||||
hostNames = server.value.hostnames;
|
||||
};
|
||||
})
|
||||
(inputs.localLib.attrsToList servers));
|
||||
programs.ssh =
|
||||
{
|
||||
startAgent = true;
|
||||
enableAskPassword = true;
|
||||
askPassword = "${inputs.pkgs.systemd}/bin/systemd-ask-password";
|
||||
extraConfig = "AddKeysToAgent yes";
|
||||
};
|
||||
environment.sessionVariables.SSH_ASKPASS_REQUIRE = "prefer";
|
||||
nixos.user.sharedModules =
|
||||
[(hmInputs: {
|
||||
config.programs.ssh =
|
||||
{
|
||||
enable = true;
|
||||
controlMaster = "auto";
|
||||
controlPersist = "1m";
|
||||
compression = true;
|
||||
matchBlocks = builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
(host: { name = host; value = { inherit host; hostname = "${host}.chn.moe"; }; })
|
||||
[ "vps6" "wireguard.vps6" "vps7" "wireguard.vps7" "wireguard.nas" ])
|
||||
++ (builtins.map
|
||||
(host: { name = host; value = { inherit host; hostname = "${host}.chn.moe"; forwardX11 = true; }; })
|
||||
[ "wireguard.pc" "wireguard.surface" "wireguard.xmupc1" "wireguard.xmupc2" ])
|
||||
++ (builtins.map
|
||||
(host:
|
||||
{
|
||||
name = host;
|
||||
value =
|
||||
{
|
||||
host = host;
|
||||
hostname = "hpc.xmu.edu.cn";
|
||||
user = host;
|
||||
setEnv.TERM = "chn_unset_ls_colors:xterm-256color";
|
||||
};
|
||||
})
|
||||
[ "wlin" "hwang" ])
|
||||
)
|
||||
// {
|
||||
xmupc1 = { host = "xmupc1"; hostname = "xmupc1.chn.moe"; port = 6007; forwardX11 = true; };
|
||||
xmupc2 = { host = "xmupc2"; hostname = "xmupc2.chn.moe"; port = 6394; forwardX11 = true; };
|
||||
nas = { host = "nas"; hostname = "office.chn.moe"; port = 5440; };
|
||||
pc = { host = "pc"; hostname = "office.chn.moe"; port = 3673; forwardX11 = true; };
|
||||
surface = { host = "surface"; hostname = "192.168.1.166"; forwardX11 = true; };
|
||||
gitea = { host = "gitea"; hostname = "ssh.git.chn.moe"; };
|
||||
jykang =
|
||||
{
|
||||
host = "jykang";
|
||||
hostname = "hpc.xmu.edu.cn";
|
||||
user = "jykang";
|
||||
forwardAgent = true;
|
||||
extraOptions.AddKeysToAgent = "yes";
|
||||
};
|
||||
};
|
||||
};
|
||||
})];
|
||||
};
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
inputs:
|
||||
{
|
||||
config = inputs.lib.mkIf (builtins.elem "server" inputs.config.nixos.packages._packageSets)
|
||||
{
|
||||
services.openssh.knownHosts =
|
||||
let
|
||||
servers =
|
||||
{
|
||||
vps6 =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO5ZcvyRyOnUCuRtqrM/Qf+AdUe3a5bhbnfyhw2FSLDZ";
|
||||
hostnames = [ "vps6.chn.moe" "wireguard.vps6.chn.moe" "74.211.99.69" "192.168.83.1" ];
|
||||
};
|
||||
"initrd.vps6" =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB4DKB/zzUYco5ap6k9+UxeO04LL12eGvkmQstnYxgnS";
|
||||
hostnames = [ "initrd.vps6.chn.moe" "74.211.99.69" ];
|
||||
};
|
||||
vps7 =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF5XkdilejDAlg5hZZD0oq69k8fQpe9hIJylTo/aLRgY";
|
||||
hostnames = [ "vps7.chn.moe" "wireguard.vps7.chn.moe" "ssh.git.chn.moe" "95.111.228.40" "192.168.83.2" ];
|
||||
};
|
||||
"initrd.vps7" =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGZyQpdQmEZw3nLERFmk2tS1gpSvXwW0Eish9UfhrRxC";
|
||||
hostnames = [ "initrd.vps7.chn.moe" "95.111.228.40" ];
|
||||
};
|
||||
nas =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIktNbEcDMKlibXg54u7QOLt0755qB/P4vfjwca8xY6V";
|
||||
hostnames = [ "wireguard.nas.chn.moe" "[office.chn.moe]:5440" "192.168.1.185" "192.168.83.4" ];
|
||||
};
|
||||
"initrd.nas" =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAoMu0HEaFQsnlJL0L6isnkNZdRq0OiDXyaX3+fl3NjT";
|
||||
hostnames = [ "initrd.nas.chn.moe" "[office.chn.moe]:5440" "192.168.1.185" ];
|
||||
};
|
||||
surface =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFdm3DcfHdcLP0oSpVrWwIZ/b9lZuakBSPwCFz2BdTJ7";
|
||||
hostnames = [ "192.168.1.166" "wireguard.surface.chn.moe" "192.168.83.5" ];
|
||||
};
|
||||
pc =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMSfREi19OSwQnhdsE8wiNwGSFFJwNGN0M5gN+sdrrLJ";
|
||||
hostnames = [ "wireguard.pc.chn.moe" "[office.chn.moe]:3673" "192.168.1.105" "192.168.83.3" ];
|
||||
};
|
||||
hpc =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDVpsQW3kZt5alHC6mZhay3ZEe2fRGziG4YJWCv2nn/O";
|
||||
hostnames = [ "hpc.xmu.edu.cn" ];
|
||||
};
|
||||
github =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl";
|
||||
hostnames = [ "github.com" ];
|
||||
};
|
||||
xmupc1 =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINTvfywkKRwMrVp73HfHTfjhac2Tn9qX/lRjLr09ycHp";
|
||||
hostnames = [ "[office.chn.moe]:6007" "[xmupc1.chn.moe]:6007" "wireguard.xmupc1.chn.moe" "192.168.83.6" ];
|
||||
};
|
||||
xmupc2 =
|
||||
{
|
||||
ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJZ/+divGnDr0x+UlknA84Tfu6TPD+zBGmxWZY4Z38P6";
|
||||
hostnames = [ "[xmupc2.chn.moe]:6394" "wireguard.xmupc2.chn.moe" "192.168.83.7" ];
|
||||
};
|
||||
};
|
||||
in builtins.listToAttrs (builtins.concatLists (builtins.map
|
||||
(server:
|
||||
(
|
||||
if builtins.pathExists ./ssh/${server.name}_rsa.pub then
|
||||
[{
|
||||
name = "${server.name}-rsa";
|
||||
value =
|
||||
{
|
||||
publicKey = builtins.readFile ./ssh/${server.name}_rsa.pub;
|
||||
hostNames = server.value.hostnames;
|
||||
};
|
||||
}]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
if builtins.pathExists ./ssh/${server.name}_ecdsa.pub then
|
||||
[{
|
||||
name = "${server.name}-ecdsa";
|
||||
value =
|
||||
{
|
||||
publicKey = builtins.readFile ./ssh/${server.name}_ecdsa.pub;
|
||||
hostNames = server.value.hostnames;
|
||||
};
|
||||
}]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
if server.value ? ed25519 then
|
||||
[{
|
||||
name = "${server.name}-ed25519";
|
||||
value =
|
||||
{
|
||||
publicKey = server.value.ed25519;
|
||||
hostNames = server.value.hostnames;
|
||||
};
|
||||
}]
|
||||
else []
|
||||
))
|
||||
(inputs.localLib.attrsToList servers)));
|
||||
programs.ssh =
|
||||
{
|
||||
startAgent = true;
|
||||
enableAskPassword = true;
|
||||
askPassword = "${inputs.pkgs.systemd}/bin/systemd-ask-password";
|
||||
extraConfig = "AddKeysToAgent yes";
|
||||
};
|
||||
environment.sessionVariables.SSH_ASKPASS_REQUIRE = "prefer";
|
||||
nixos.user.sharedModules =
|
||||
[(hmInputs: {
|
||||
config.programs.ssh =
|
||||
{
|
||||
enable = true;
|
||||
controlMaster = "auto";
|
||||
controlPersist = "1m";
|
||||
compression = true;
|
||||
matchBlocks = builtins.listToAttrs
|
||||
(
|
||||
(builtins.map
|
||||
(host: { name = host; value = { inherit host; hostname = "${host}.chn.moe"; }; })
|
||||
[
|
||||
"vps6" "wireguard.vps6" "vps7" "wireguard.vps7" "wireguard.pc" "wireguard.nas" "wireguard.surface"
|
||||
"wireguard.xmupc1" "wireguard.xmupc2"
|
||||
])
|
||||
++ (builtins.map
|
||||
(host:
|
||||
{
|
||||
name = host;
|
||||
value =
|
||||
{
|
||||
host = host;
|
||||
hostname = "hpc.xmu.edu.cn";
|
||||
user = host;
|
||||
extraOptions.SetEnv = "TERM=chn_unset_ls_colors:xterm-256color";
|
||||
};
|
||||
})
|
||||
[ "wlin" "hwang" ])
|
||||
)
|
||||
// {
|
||||
xmupc1 = { host = "xmupc1"; hostname = "xmupc1.chn.moe"; port = 6007; };
|
||||
xmupc2 = { host = "xmupc2"; hostname = "xmupc2.chn.moe"; port = 6394; };
|
||||
nas = { host = "nas"; hostname = "office.chn.moe"; port = 5440; };
|
||||
pc = { host = "pc"; hostname = "office.chn.moe"; port = 3673; };
|
||||
surface = { host = "surface"; hostname = "192.168.1.166"; };
|
||||
gitea = { host = "gitea"; hostname = "ssh.git.chn.moe"; };
|
||||
jykang =
|
||||
{
|
||||
host = "jykang";
|
||||
hostname = "hpc.xmu.edu.cn";
|
||||
user = "jykang";
|
||||
forwardAgent = true;
|
||||
extraOptions.SetEnv =
|
||||
# in .bash_profile:
|
||||
# if [[ $TERM == chn_unset_ls_colors* ]]; then
|
||||
# export TERM=${TERM#*:}
|
||||
# export CHN_LS_USE_COLOR=1
|
||||
# fi
|
||||
# if [[ $TERM == chn_cd* ]]; then
|
||||
# export TERM=${TERM#*:}
|
||||
# cd ~/${TERM%%:*}
|
||||
# export TERM=${TERM#*:}
|
||||
# fi
|
||||
# in .bashrc
|
||||
# [ -n "$CHN_LS_USE_COLOR" ] && alias ls="ls --color=auto"
|
||||
let
|
||||
usernameMap =
|
||||
{
|
||||
chn = "linwei/chn";
|
||||
xll = "linwei/Xll";
|
||||
yjq = "linwei/yjq";
|
||||
gb = "kangjunyong/gongbin";
|
||||
};
|
||||
cdString =
|
||||
if usernameMap ? ${hmInputs.config.home.username} then
|
||||
":chn_cd:${usernameMap.${hmInputs.config.home.username}}"
|
||||
else "";
|
||||
in "TERM=chn_unset_ls_colors${cdString}:xterm-256color";
|
||||
};
|
||||
};
|
||||
};
|
||||
})];
|
||||
};
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
@@ -1 +0,0 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
|
||||
@@ -1 +0,0 @@
|
||||
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDkkl7A9kWWBoi4b5g6Vus70ja1KhPfcZZjeU1/QbYdN8PRRw/hsGklrhefslKRbym/TMFS0ko0g5WUi9G5vbGw=
|
||||
@@ -1 +0,0 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgs8MvV2nczjGMZ548tuAhgvCEd4uHu0VhLDSwQG7Nh/UR4Pgc5T9Nf7Vfwg96Lah/pwD5my4RaWis6bLMmlkYyDBKFBOsGYQUe5J5XfZdxk8pz+7L0Hq6gPfAZAdNlUiuFVKsvkE+NF42NgJyXSYQicPbu5LQiFwZGXlW20+LO8uBQ1y1xabKVpg8XGwordduL99VepwEzeLK/st+UVfW+mKgxkf9TuxvD2fuYIDZM7y2rXqcjf4/6OXA5kACsYK1MgZSFxgO/m6+1uCC1qBDseMTA3D+Tsjf9VtcqUE9dMd/dJ/uuILHJ0+oIqkykTCecPLgJY3Vh8rAtln/lbId
|
||||
@@ -1 +0,0 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC0+xafJMnOGCHv6OLljaq8iJ3ZBaIezv7AJ9rVWJXFg/QJRYBwct35c4zaVom7If8F+Ss+BTLMp33HZ8gLpoat6LkjARjy65Ycog3NOnEposX2JjZEYXDbovxEmcJkDXAIVmnaBUi3r22z4UI8OqsHPeRXj017O0yQrQQYEAw/IO/tSNQZt2k8JHxAX50UTqGFdgkriO1fYHBocq48m0nn3sXrMuM3yBe5zy3NngOHxMn7UxjECmAElsuu/nu1x083pRnv5NSa+JxDGJ+S6Zhj3nGGNwZesa51I4cJjsYLxgmO/NxL1J86bDp6HhK9C9799ruG60pGTw6HcvbKTgx7klUgn4936wsy7qukWqp53MvqrLSJkRb/HHU9zZqvzcjbwet+Iv1OAAok5QC88j7Jgenk3nbZw4BNFd2r/8rOZuXheDnMKOa61dXxnvoAO3Euk0RPdZqW1slT/DDyD/kB6TPY7yOywNURNnrwzfSsmravKi6bGA5t2Ehhpf2LETM=
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user