SIESTA编译、资源整理

1.编译安装

本文还是以intel oneapi环境为例,siesta的编译非常简单。官方源码在GitLab发布,可以在https://gitlab.com/siesta-project/siesta/-/releases获取软件包,以siesta-v4.1.5版本为例,下载siesta-v4.1.5.tar.gz并解压,进入该文件夹。

mkdir build 
cd build

bash ../Src/obj_setup.sh
cp ../Obj/intel.make ./arch.make

这里我们需要对arch.make进行修改,主要是需要修改两个地方,首先根据实际情况修改需要用到的编译器,这里我使用了mpicc和mpiifort

CC = mpicc
FPP = $(FC) -E -P
FC = mpiifort
FC_SERIAL = ifort

其次是我们需要使用MKL的BLAS,在Dependency rules ———一行之前的位置加入下面的内容,如果将这部分放在文件开头,可能会被后面的命令给覆盖导致无效

MKL_PATH=根据实际情况填写
BLAS_LIBS=-L$(MKL_PATH) -lmkl_intel_lp64 -lmkl_sequential -lmkl_core -lpthread -lmkl_blacs_intelmpi_lp64 -lmkl_scalapack_lp64
LAPACK_LIBS=
BLACS_LIBS=
SCALAPACK_LIBS=
LIBS =$(SCALAPACK_LIBS) $(BLACS_LIBS) $(LAPACK_LIBS) $(BLAS_LIBS)

MPI_INTERFACE = libmpi_f90.a
MPI_INCLUDE = .
FPPFLAGS += -DMPI

这里如果不清楚MKL的安装目录,可以使用下面的命令来获取

MKL_PATH=$(echo $MKLROOT | awk -F: '{ print $1 }')
echo $MKL_PATH

之后使用make -jN进行编译(N为核心数),我们就可以在当前目录下得到siesta的二进制文件了。

参考:

https://zhuanlan.zhihu.com/p/609209355

2.赝势获取

SIESTA提供了一个生成赝势的程序ATOM,对于学术用户是免费的,可以在https://siesta-project.org/SIESTA_MATERIAL/Pseudos/atom_licence.html进行获取。我们也可以从下面几个赝势库获取生成好的赝势直接使用:

3.辅助软件

在LAMMPS中使用NequIP的方法

之前我们介绍过在LAMMPS中使用CHGNet的方法,最近,具有E(3)等变的NequIP也得到了很多的关注,笔者测试也觉得在很多场景下其相比CHGNet会更加好用,在这里介绍一下安装加入了NequIP pair style的Lammps安装方法。

1.安装Conda

2.新建Conda环境

由于NequIP对于Python和PyTorch版本有以下要求:

  • Python >= 3.7
  • PyTorch >= 1.8, !=1.9, <=1.11.*.

NequIP也要求PyTorch or LibTorch >= 1.10.0。

综合考虑我们选择Python 3.8+PyTorch 1.11.0环境,而且注意如果只是用NequIP不需要装torchvision和torchaudio,可以节省空间。这里Wandb是用来可视化训练日志的工具Weights & Biases,如果没有需求可以不装。

conda create -n nequip python=3.8
conda activate nequip

pip install wandb
conda install pytorch=1.11.0 cpuonly -c pytorch
pip install nequip

3.下载LAMMPS

从LAMMPS官方Github仓库下载LAMMPS stable_29Sep2021_update2版本,以及下载NequIP pair style。

git clone -b stable_29Sep2021_update2 --depth 1 [email protected]:lammps/lammps
git clone [email protected]:mir-group/pair_nequip

进入pair_nequip目录,执行

./patch_lammps.sh /path/to/lammps/

其中/path/to/lammps/是刚才下载的LAMMPS源码位置。,该脚本会自动完成pair style复制以及CMakeLists的修改。

4.编译

接下来使用Intel Oneapi进行编译,自行加载相应环境。

cd lammps
mkdir build
cd build
cmake ../cmake -DCMAKE_PREFIX_PATH=`python -c 'import torch;print(torch.utils.cmake_prefix_path)'`

make -j$(nproc)

完成后/path/to/lammps/build/lmp即为我们所需的支持NequIP的LAMMPS二进制文件。不过需要注意的是,由于消息传递神经网络的特点,NequIP不支持MPI,该课题组还有支持MPI和并行加速的程序Allegro(https://github.com/mir-group/allegro)。

NequIP官方仓库:

https://github.com/mir-group/nequip

https://github.com/mir-group/pair_nequip

OCTOPUS编译记录

最近打算试一试td-dft计算,查阅了一些文献发现OCTOPUS似乎比较合适。由于软件比较冷门,而且官方文档对于使用Intel编译器进行编译的方法写的并不清楚,因此编译过程中遇到了不少坑,在此记录一下我的编译方法,希望能够帮助到后来人。

1.安装Intel oneAPI

在Intel官网(https://www.intel.com/content/www/us/en/developer/tools/oneapi/toolkits.html)获取Intel® oneAPI Base Toolkit和Intel® oneAPI HPC Toolkit,并按照页面指示安装,配置环境变量

安装Octopus需要依赖BLAS、LAPACK、FFTW 3,由于我们使用了Intel oneAPI,我们可以直接调用Intel MKL,无需再手动安装了,但除此之外的GSL和LibXC仍是必须手动安装的依赖。

2.安装LibXC

libxc通过gitlab进行发布,官方下载地址https://gitlab.com/libxc/libxc/-/releases

由于libxc的cmake安装方式还不完善,推荐使用make进行安装,如果没有./configure文件,需要先运行GNU autotools生成。PATH/TO/LIBXC是LibXC的安装路径。

autoreconf -i
./configure --prefix=PATH/TO/LIBXC CC=mpiicc CXX=mpiicpc FC=mpiifort
make
make install

3.安装GSL

GSL也同样通过make方式安装,PATH/TO/GSL是GSL的安装路径。

./configure --prefix=PATH/TO/GSL CC=mpiicc 
make
make install

4.安装Octopus

首先进行configure,PATH/TO/OCTOPUS是Octopus的安装路径。这里blas的配置主要参考了官网https://www.octopus-code.org/documentation/main/manual/installation/porting_octopus_and_platform_specific_instructions/,并且由于blas已经包含了lapack所以这里我们可以将–with-lapack留空。

MKL_DIR=$(echo $MKLROOT | awk -F: '{ print $1 }')
./configure CC=mpiicc CXX=mpiicpc FC=mpiifort \
--prefix=PATH/TO/OCTOPUS \
--with-libxc-prefix=PATH/TO/LIBXC \
--with-gsl-prefix=PATH/TO/GSL \
--with-blas="-L$MKL_DIR/lib/intel64 -Wl,--start-group -lmkl_intel_lp64 -lmkl_sequential -lmkl_core -Wl,--end-group -lpthread -lmkl_blacs_intelmpi_lp64 -lmkl_scalapack_lp64 " \
FCFLAGS_FFTW=-I$MKL_DIR/include/fftw \
--enable-mpi

这里可能会遇到一个问题,如果libxc的安装目录里面的lib目录在你的系统里安装完成后叫lib64,这里configure的时候会找不到lib目录而报错,直接创建一个软连接ln -s lib64 lib即可解决这个问题。

此外,octopus的configure似乎并不是非常完善,有的时候即使报错了configure也不会提示,因此如果之后编译遇到问题,可以考虑检查一下日志config.log里面是否存在其他问题。

如果configure顺利,接下来就可以正式安装了。

make
make install

如果一切顺利,在PATH/TO/OCTOPUS的bin目录下面就有我们所需的octopus二进制文件了,share目录下也提供了一些可供测试的示例,我们就可以运行软件进行测试了。

参考:

https://cndaqiang.github.io/2020/10/19/huairou-octopus(提供了不同编译环境的安装方法及简单测试)

https://www.cnblogs.com/HuaNeedsPills/p/12732926.html(Intel环境下的编译)

https://blog.csdn.net/ChenXiao93/article/details/95769666(Onpenmpi环境下的编译)

https://blog.csdn.net/qq_34718338/article/details/123039137

https://cndaqiang.github.io/2019/04/11/octopus

使用Zotero快速为幻灯片引文

一般做幻灯片都要用短引文格式,使用Zotero可以很方便的复制引文。

在这里找到需要参考的样式:https://editor.citationstyles.org/about/。

使用可视化的CSL编辑器删掉不需要的部分,调整格式(例如将期刊名调整为缩写)https://editor.citationstyles.org/visualEditor/。

导入Zotero,使用快捷键Ctrl+Shift+C即可快速复制参考文献样式,粘贴到幻灯片中即可使用了。

继续阅读“使用Zotero快速为幻灯片引文”

离线编译支持HDF5的Quantum Espresso并使用Perturbo(以QE 7.0版本为例)

0.前言

Perturbo是用于计算电荷传输和材料中超快载流子动力学的第一性原理的软件包。主要着重于电子-声子相互作用,并可以计算声子限制的传输特性,例如电导率,载流子迁移率和塞贝克系数。它也可以在存在电子-声子散射的情况下模拟超快非平衡电子动力学,为定量研究金属,半导体,绝缘体和2D材料中的电子-声子相互作用和载流子动力学提供了有效的计算工具。由于编译Perturbo需要用到支持HDF5版本的QE程序,编译过程较为繁琐,因此在此记录一下编译的全部过程。

1.安装Intel Oneapi

在Intel官网(https://www.intel.com/content/www/us/en/developer/tools/oneapi/toolkits.html)获取Intel® oneAPI Base Toolkit和Intel® oneAPI HPC Toolkit,并按照页面指示安装,配置环境变量

2.安装HDF5库

在这里统一使用Intel编译器进行编译,并且我们需要使用–enable-fortran选项来支持fortran。可以使用本文提供的一键脚本进行快速编译,也可参照脚本内容进行手动操作。

将下面的脚本保存为install.sh,执行即可自动下载HDF5库并安装。如果离线安装需要在脚本目录下建立_tmp文件夹,并将下载好的HDF5库hdf5.tar.gz手动放入再执行即可。

#!/bin/bash

# Specify the installation directory
INSTALL_DIR=./hdf5
TMP_DIR=_tmp

# Convert INSTALL_DIR to an absolute path
INSTALL_DIR=$(readlink -f $INSTALL_DIR)

# Specify the installation version
HDF5_VERSION=1_14_2

# Branch name
BRANCH_NAME=hdf5_$HDF5_VERSION

# Check if INSTALL_DIR exists, if not, create it
if [ ! -d "$INSTALL_DIR" ]; then
    mkdir -p $INSTALL_DIR
fi

# Check if Intel oneAPI environment has been sourced
if [ "$MKLROOT" == "" ]; then
    echo "Error: Intel oneAPI environment is not detected. Please source Intel oneAPI environment first."
    exit 1
fi

# Create _pkgs directory
mkdir -p $TMP_DIR

# Download the specified version of HDF5 from GitHub as a tar.gz package, skip if already downloaded
if [ ! -f "$TMP_DIR/hdf5.tar.gz" ]; then
    wget -O $TMP_DIR/hdf5.tar.gz https://github.com/HDFGroup/hdf5/archive/refs/heads/$BRANCH_NAME.tar.gz
fi

# Extract the tar.gz package
tar -xzf $TMP_DIR/hdf5.tar.gz -C $TMP_DIR
cd $TMP_DIR/hdf5-$BRANCH_NAME

# Configure HDF5 with parallel support enabled and specify the installation directory
FC=ifort CC=icc CXX=icpc ./configure --prefix=$INSTALL_DIR --enable-fortran

# Compile
make -j4

# Install
make install

# Clear the folder in _pkgs directory, keep the tar.gz package
cd ../..
rm -rf $TMP_DIR

echo "HDF5 has been successfully installed to $INSTALL_DIR"

3.编译Quantum Espresso

(1)下载源码https://github.com/QEF/q-e/releases/并解压。

(2)进行configure,需要指定HDF5库路径,将/path/to/hdf5换成刚才安装的实际hdf5库路径

./configure --with-hdf5=yes --with-hdf5-libs="-L/path/to/hdf5/lib -lhdf5 -lhdf5_fortran" --with-hdf5-include="/path/to/hdf5/include"

完成configure之后,检查屏幕上的提示,如果有类似下面的内容,说明配置成功。

The following libraries have been found:
BLAS_LIBS= -lmkl_intel_lp64 -lmkl_sequential -lmkl_core
LAPACK_LIBS=
FFT_LIBS=
HDF5_LIBS=-L/path/to/hdf5/lib -lhdf5 -lhdf5_fortran

如果没有正确显示HDF5_LIBS,说明可能需要检查上面的HDF5库路径是否正确(如lib和lib64得区别),或者尝试使用–with-hdf5=”/path/to/hdf5″替代上面的命令。如果BLAS_LIBS没有MKL,说明可能没有正确使用Intel编译器的环境变量。

(3)准备devicexlib

在较新版本的QE中,编译时会联网获取devicexlib库,这对于离线安装非常不友好。观察编译过程发现在进行下载前其会先判断./external/devxlib目录下是否存在可以configure的文件再进行下都,因此可以手动下载该库来解决这个问题。

首先在https://gitlab.com/max-centre/components/devicexlib/-/archive/0.1.0/devicexlib-0.1.0.tar.gz获取该库,放置于目录./external/devxlib内,再通过命令tar xzf devicexlib-0.1.0.tar.gz –strip-components=1 -C .解压。

(4)编译

使用make all -jN(N为编译使用的核数)进行编译即可。

如果一切顺利,./bin目录下会出现各模块的二进制文件了。

4.运行Quantum Espresso

之后可以测试一下刚编译的QE程序,运行时需要添加HDF5库的环境变量

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/hdf5/lib

5.安装Perturbo

(1)找到官方文档(https://perturbo-code.github.io/mydoc_installation.html)给出的申请表格地址,填写个人信息,邮箱会收到自动发送的程序源码。根据官方的版本适配信息(https://perturbo-code.github.io/mydoc_versions.html),选择与QE版本相兼容合适的Perturbo版本,如QE 7.0需要使用2.0,QE 7.2需要使用2.1。下载源码并解压,放置于QE源码的根目录,也就是和其他内置模块一样。

(2)修改make.sys

进入perturbo目录,编辑make.sys,找到下面两行,去掉注释并修改HDF5目录为实际HDF5目录。

IFLAGS += -I/path/to/hdf5/include
HDF5_LIBS = -L/path/to/hdf5/lib -lhdf5 -lhdf5_fortran

注:对于较新版本,可能需要先使用下面的命令复制.sys到perturbo的根目录

cp config/make_gcc_serial.sys make.sys

之后可以执行make进行编译,如果编译成功,可以在./perturbo/bin目录下找到编译好的二进制文件了。

Perturbo官网提供了丰富的使用样例(https://perturbo-code.github.io/mydoc_org.html),可参考官网样例学习输入格式,进行练习和测试。

6.安装Wannier 90

在Wannier 90官网(https://wannier.org/download/)获取最新版本Wannier 90的源代码,应该是压缩包格式的,如v3.1.0.tar.gz。

放入QE源码根目录下面的archive文件夹,并将压缩包改名为版本号,如./archive/v3.1.0,这里不需要后缀名。

回到根目录,执行编译命令。

make w90

在LAMMPS中使用CHGNet

0.前言

CHGNet是一种基于图神经网络的机器学习原子势,近期发表于Nature Machine Intelligence volume 5, pages1031–1041 (2023)。笔者注意到近期有开发者已经完成了CHGNet的LAMMPS接口(https://github.com/CederGroupHub/chgnet/issues/57)。但目前网络上还没有相关的使用教程,因此在此记录一下笔者编译以及测试的过程。

此教程也可用于M3GNet和MatGL接口的使用。

1.安装并配置Anaconda

由于CHGNet使用Python实现,因此需要先确保服务器配置了Python环境,如果没有安装推荐安装Anaconda(官方文档:https://docs.anaconda.com/free/anaconda/install/linux/)来配置Python环境。并需要确保已经安装了chgnet,可以使用下面的命令进行安装。

pip install chgnet

2.获取源代码

实现了CHGNet接口的LAMMPS程序源码可以在Github上获取到(https://github.com/advancesoftcorp/lammps)。提供了2Aug2023和2Aug2023两个版本可供选择,下载源码并解压。Lammps提供了基于CMake和make的两种编译方式,本文使用make进行编译。

3.修改Makefile

进入下载好的源代码的./src/MAKE目录,找到Makefile文件。由于CHGNet接口仅支持调用GPU和OpenMP,而不支持MPI并行,因此本文以编译串行(Serial)版本为例,也就是修改Makefile.serial。共有三处需要修改。

(1)修改CCFLAGS和LINKFLAGS(如果需要使用OpenMP)

根据官网文档(https://docs.lammps.org/Build_extras.html#openmp),使用OpenMP需要修改compiler/linker settings部分的下面两行,加入-fopenmp参数。

CCFLAGS = -g -O3 -std=c++11 -fopenmp
LINKFLAGS = -g -O -std=c++11 -fopenmp

如果使用Intel编译器,则需要将CCFLAGS替换成-qopenmp -restrict,LINKFLAGS替换成-qopenmp。

(2)加入Python相关的includes和library变量

在Makefile的build rules and dependencies之前的位置加入下列内容,your_path/anaconda3需要替换成本地实际的Python路径,python3.x需要替换成实际的python版本号,如python3.11,如果不确定可以通过find命令进行查找。这里需要注意如果服务器上有多个Python环境,务必使用安装了chgnet的环境的路径进行添加

# Python library and includes (for conda)
PYTHON_INC = -I/your_path/anaconda3/include/python3.x
PYTHON_LIB = -L/your_path/anaconda3/lib -lpython3.x

(3)修改EXTRA_INC和EXTRA_LIB,加入Python的相关变量

这两行位于build rules and dependencies部分,分别加入$(PYTHON_INC)和$(PYTHON_LIB)。

EXTRA_INC = $(LMP_INC) $(PKG_INC) $(MPI_INC) $(FFT_INC) $(JPG_INC) $(PYTHON_INC) $(PKG_SYSINC)
EXTRA_LIB = $(PKG_LIB) $(MPI_LIB) $(FFT_LIB) $(JPG_LIB) $(PYTHON_LIB) $(PKG_SYSLIB) $(DYN_LIB)

修改好Makefile后,我们就可以回到./src目录,开始正式的编译安装了。

4.编译安装

LAMMPS在编译时,如果需要编译额外的可选包,需要使用如下的命令,name需要替换成实际的包名(https://docs.lammps.org/Build_extras.html):

make yes-name

同理也可以使用make no-name删除某个可选包。

在这里,我们需要加入CHGNet和OpenMP(可选),即

make yes-OPENMP
make yes-ML-CHGNET

之后进行正式编译,将-jN中的N替换为编译实际使用的核数。

make serial -jN

这里特别提醒,如果之前编译过其他版本,需要使用下面的命令进行清理再重新进行编译。

make clean-all

完成编译后,如果没有报错,src目录下应该出现了名为lmp_serial的二进制文件,即为我们编译的LAMMPS程序了。可以复制到其他目录,配置环境变量,以方便使用。

5.运行测试

在./examples/CHGNET,我们可以看到开发者提供的输入样例inp.lammps,其中pair_style和pair_coeff格式如下:

pair_style chgnet ../../potentials/CHGNET 
#pair_style chgnet/d3 ../../potentials/CHGNET 
#pair_style chgnet/gpu ../../potentials/CHGNET 
#pair_style chgnet/d3/gpu ../../potentials/CHGNET
# 使用MPtrj预训练模型
pair_coeff    * *  MPtrj-efsm  Zr O
# 使用自己的pt模型
pair_coeff    * *  path ./users_model.pt  Zr O

使用命令env OMP_NUM_THREADS=N lmp_serial -sf omp -in inp.lammps,我们可以使用N个OpenMP threads来执行任务。OpenMP的使用细节可以参考官方文档:https://docs.lammps.org/Speed_omp.html。

此外,需要注意的是,如果要在集群的作业系统上提交,我们还需要在作业脚本中加入LD_LIBRARY_PATH环境变量,与Makefile中的修改类似,将/your_path/anaconda3改成实际的Python目录:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/your_path/anaconda3/lib

6.常见问题

(1)LAMMPS运行时警告:WARNING: OpenMp support not enabled during compilation: using 1 thread only.

检查Makefile是否有加入-fopenmp,以及是否有启用make yes-OPENMP。

(2)LAMMPS运行时报错:ERROR: Cannot initialize python for pair_coeff of CHGNet

说明CHGNet的Python环境未正确配置,需要调整Python环境。

使用Material Project时需要注意的能量修正问题

当我们在某些计算问题中需要比较Material Project(MP)的能量数据与本地DFT的计算结果时,如形成能的计算(https://blog.csdn.net/qq_36996539/article/details/128066249)。经过测试发现,即使在使用相同的输入参数的情况下,这两种方法得到的结果可能会有所不同。通过查阅Material Project官方文档,才发明很多人可能忽略了MP中对于能量进行的修正,这对于比较能量是非常重要的。

在MP中,为了提高其DFT计算的准确性,采用了两种修正:阴离子修正GGA/GGA+U混合修正

  1. 阴离子修正:
    • 对于许多在固体中呈负氧化态的元素,由于元素和固体之间电子定位的差异,从DFT计算得到的形成能可能存在显著的误差。这对于其标准状态为气态的元素尤为明显。
    • 为了解决这个问题,MP对14种阴离子应用了能量修正,包括“氧化物”(oxides)、“过氧化物”(peroxide)、“超氧化物”(superoxides)、S、F、Cl、Br、I、N、H、Se、Si、Sb和Te。
    • 对于含氧化物的化合物,根据氧在材料中的特定键合环境,分为氧化物、超氧化物和过氧化物的修正,根据最近邻键长确定的(超氧化物<1.35 Å,过氧化物<1.49 Å,否则为氧化物)。例如,Na2O接收’氧化物’修正,而NaO2接收超氧化物修正。
    • 只有当材料中被修正的元素作为阴离子时,才应用阴离子修正。例如,’H’修正应用于LiH,但不应用于H2O。如果估计的氧化态(如果可用)为负,或者它是材料中最具电负性的元素,那么它被分类为阴离子。
    • 具体数值可以参考参考文献1。
  2. GGA / GGA+U混合修正:
    • 众所周知,对于不同的化合物有些适用于+U修正计算,而其他化合物通常不采用。带有+U修正的能量与不带+U修正的能量不直接可比
    • MP中,GGA+U计算的结果添加了能量修正项,从而使得两种计算结果可以混合比较。

References:

  1. 1.A. Jain, G. Hautier, C. Moore, S.P. Ong, C.C. Fischer, T. Mueller, K.A. Persson, G. Ceder., A High-Throughput Infrastructure for Density Functional Theory Calculations, Computational Materials Science, vol. 50, 2011, pp. 2295-2310. DOI:10.1016/j.commatsci.2011.02.023
  2. 2.A. Jain, G. Hautier, S.P. Ong, C. Moore, C.C. Fischer, K.A. Persson, G. Ceder, Accurate Formation Enthalpies by Mixing GGA and GGA+U calculations, Physical Review B, vol. 84, 2011, p. 045115. DOI:10.1103/PhysRevB.84.045115
  3. Anion and GGA/GGA+U Mixing – Materials Project Documentation

漫画汉化中的一些批量处理(Adobe Photoshop&Python)

在做汉化过程中,经常会有一些批量处理的问题。一些简单的操作可以直接使用 Photoshop 解决,稍微复杂的问题使用 Python 的 Pillow 库会更加方便。

Photoshop 提供了一些非常简便的批量处理功能,在窗口—动作中可以通过使用软件预设的动作或者自行录制动作来实现一系列简单的重复动作。

在文件—自动—批处理中,就可以应用这些动作进行批量处理了。但是 Photoshop 自带的批处理并不是非常好用,使用起来局限性较大,效率也不理想。

只要熟悉 Python 的 Pillow 库,我们可以很快速的根据需求编写各种批量处理脚本,下面提供几个在实际汉化过程中用到的简单例子作为参考。

使用之前不要忘了安装 Pillow 库:

pip install Pillow

1.裁切并调整尺寸
def resize_and_crop_image(input_path, output_path, target_size):
    try:
        # 打开图像文件
        image = Image.open(input_path)

        # 计算缩放比例
        width_ratio = target_size[0] / image.width
        height_ratio = target_size[1] / image.height
        resize_ratio = min(width_ratio, height_ratio)

        # 计算缩放后的尺寸
        new_width = int(image.width * resize_ratio)
        new_height = int(image.height * resize_ratio)

        # 缩放图像
        image = image.resize((new_width, new_height), Image.ANTIALIAS)

        # 计算裁切的位置
        left = (new_width - target_size[0]) / 2
        top = (new_height - target_size[1]) / 2
        right = (new_width + target_size[0]) / 2
        bottom = (new_height + target_size[1]) / 2

        # 裁切图像
        image = image.crop((left, top, right, bottom))
        image.save(output_path, dpi=(600, 600))

        print(f"已处理文件: {input_path}")
    except Exception as e:
        print(f"处理文件{input_path}时出错: {str(e)}")

2.整页扫描时分页
def split_image(image_path):
    # 打开图片
    with Image.open(image_path) as img:
        # 获取图片的宽和高
        width, height = img.size
        
        # 计算中间位置
        middle = width // 2
        
        # 切割图片
        left_img = img.crop((0, 0, middle, height))
        right_img = img.crop((middle, 0, width, height))
        
        # 获取原始文件名中的两个数字
        base_name = os.path.splitext(image_path)[0]
        num1, num2 = base_name.split('、')
        
        # 保存切割后的图片
        left_img.save(f"{num1}.png")
        right_img.save(f"{num2}.png")

3.添加图片水印
def add_watermark(input_image_path, output_image_path, watermark_image_path, transparency, scale):
    original = Image.open(input_image_path)
    watermark = Image.open(watermark_image_path)
    watermark = watermark.convert("RGBA")

    # 设置透明度
    datas = watermark.getdata()
    new_data = []
    for item in datas:
        new_data.append((item[0], item[1], item[2], int(item[3] * transparency)))
    watermark.putdata(new_data)

    # 缩放
    watermark = watermark.resize((int(watermark.width * scale), int(watermark.height * scale)))

    # 将水印放在左下角
    original.paste(watermark, (0, original.height - watermark.height), watermark)
    original.save(output_image_path)
4.文字水印
def add_watermark(image_path, watermark_text, output_path):
    # 打开图片
    image = Image.open(image_path).convert("RGBA")
    
    # 字体和字体大小
    font = ImageFont.truetype("C:/Windows/Fonts/arial.ttf", 80)
    
    # 计算水印文字的宽和高
    text_width, text_height = ImageDraw.Draw(image).textsize(watermark_text, font)

    # 创建一个单独的水印图像
    watermark = Image.new('RGBA', (text_width, text_height), (255, 255, 255, 0))
    draw = ImageDraw.Draw(watermark)
    draw.text((0, 0), watermark_text, font=font, fill=(255, 255, 255, 100))

    # 旋转水印图像
    watermark = watermark.rotate(45, expand=1)

    # 获取图片的宽和高
    width, height = image.size

    # 创建一个可以在其上进行绘画的图像,初始颜色为透明
    txt = Image.new('RGBA', image.size, (255,255,255,0))

    # 将旋转后的水印复制到新创建的图像上
    for i in range(0, width, watermark.width):
        for j in range(0, height, watermark.height):
            txt.paste(watermark, (i, j), watermark)

    # 合并两个图片
    watermarked = Image.alpha_composite(image, txt)

    # 将RGBA模式转换为RGB模式
    watermarked = watermarked.convert("RGB")

    # 保存加了水印的图片
    watermarked.save(output_path)

给Surface Pro 8更换硬盘

1.一个老生常谈的问题,更换硬盘影响保修吗?

我咨询了微软客服,客服的说法是:虽然一般是不建议自行更换,但若是正常的更换没有损坏是不影响保修的。后续设备若是有出现功能问题需要保修的话,可以将原来的硬盘换回去恢复然后保修就正常保修了。(2024/5更新:已经在售后实测,如果售后网点可以直接进行拆机维修的问题,即使不换回原硬盘也可正常进行保修, 但如需返厂仍然需要换回原装硬盘)

2.选择硬盘

Surface Pro 8的SSD规格是2230,这其实是一个非常尴尬的尺寸,零售的2230硬盘非常少,大部分都是OEM产品,再加上Steam Deck和Rog Ally 等掌机也采用了同样规格的硬盘,导致现在硬盘价格普遍跳水的情况下2230规格的硬盘大部分还比较坚挺,实际可以选择的型号不多。

2230规格大部分固态性能并不理想,目前的首选是SN740,算是平衡了性能和性价比最好的选择,而且也有南京梵多这种靠谱的西数代理店铺可以购买,保修也有了保障。但是奇葩的是Surface Pro 8唯独跟这款固态有着一些不兼容的问题,可能会存在蓝屏等问题,虽然确实有一些解决方案(或Github上面这个方案),但都不是完美的方案。倒是可以购买SN530作为替代,但是价格更高却有着更糟糕的性能实在是不太值得。另一个优选是PCIE3.0最强的2230固态BC711,但没有很好的购买渠道且价格一直居高不下,而且还出现了很多假货。其他选择还有铠侠的BG4和BG5。

权衡之下,我最后选择了三星的PM991,和我目前原创的256G硬盘是相同的型号。虽然在性能上比较逊色,但价格上确实比较实惠,而且也有相对比较靠谱的老店可以购买。

另外国产品牌也开始推出了一些2230固态,例如达墨的狮子座和幻隐的HV2000,还有梵想和海康威视等等牌子,如果叠加拼多多的各种优惠卷确实可能能做到不错的价格,但是来路不明的颗粒实在是不敢作为系统盘使用。希望这些品牌能够经受时间检验。

3.迁移数据or重装系统

如果需要保留机器数据,就需要准备一个硬盘盒来进行硬盘克隆了。这里我选择的是ITGZ的9210B双协议2230硬盘盒,虽然比起常见的JMS583主控价格稍微贵了一些,但是9210B主控确实在温度表现上更加出色。

之后安装DiskGenius官网的教程,使用免费版就可以使用的系统迁移功能就可以完成迁移了,整个过程非常简单。

如果不需要保留数据,只需要准备一个u盘进行重装就可以了。在微软官网就能下载用于重装的Surface恢复镜像,也不用担心丢失Windows激活。

4.拆机安装硬盘

Surface的硬盘槽就在机器背面,基本没有什么拆解难度,首先需要一个取卡针打开硬盘盖,然后需要一个T3规格的螺丝刀拧开SSD的固定螺丝就可以进行更换了。如果没有安装过固态硬盘,需要注意硬盘是斜着插入的,再通过螺丝固定放平。(因为之前没有想到用的是这么小的螺丝,没有准备对应的螺丝刀,因此紧急去小米之家买了一套小米精修螺丝刀,品质确实不错。)

5.后续问题

迁移硬盘后应用和数据都能正常使用,但BitLocker和Onedrive可能会出现一点问题。

Onedrive在重装后可能会在同步过程中出现一些问题,我按照官网教程(重置 OneDrive – Microsoft 支持)重置Onedrive,删除了无效的个人保管库快捷方式,就解决了。(注意这里微软官网教程犯了错误,应该是”C:\Program Files\Microsoft OneDrive\onedrive.exe” /reset)

BitLocker的问题就比较麻烦了,克隆硬盘后我就无法正常开启BitLocker了。我咨询了Surface官方客服和Windows客服都没有有效的解决方案,我尝试了清除TPM(更新安全处理器 (TPM) 固件 – Microsoft 支持)也没有解决。或许如果对BitLocker依赖高的话还是应该采用重装的方法。

手动编译安装gcc

代码用到了一些C++17特性,但由于集群上的GCC版本比较老旧,出现了一些难以解决的段错误,因此选择了自己手动编译一份新版本GCC来避免此类问题。编译GCC虽然不难,但是整体较为繁琐,因此在此记录一下以免遗忘。

GCC的构建需要GMP(GNU Multiple Precision Arithmetic Library,GNU多精度算术库)、MPFR(Multiple Precision Floating-Point Reliable,多精度浮点可靠库)和MPC(Multiple Precision Complex,多精度复数库)这三个库。首先需要先按顺序安装这些库,并在配置GCC时指定它们的路径。

继续阅读“手动编译安装gcc”