feat(init): add LaTeX manual scaffold and 'init manual' command
- scaffolds/manual/: ctexart+xelatex manual template (cover, TOC, colored headings, four callout boxes, listings code, booktabs three-line tables), visually aligned with Typst md-to-pdf/manual template - commands/init.py: extract _init_scaffold() shared by paper/manual - sync README/AGENTS/skill references; document templates-vs-scaffolds-vs-journals taxonomy
This commit is contained in:
@@ -8,15 +8,16 @@ mytoolkit latex compile paper.tex -e xelatex
|
||||
mytoolkit latex count paper.tex
|
||||
```
|
||||
|
||||
## 论文脚手架 / 投稿模板
|
||||
## 论文/手册脚手架 · 投稿模板
|
||||
|
||||
```bash
|
||||
mytoolkit init paper <dir> # 新建论文项目(elsarticle 脚手架,xelatex,可移植;精确配置见生成的 main.tex 头部注释,设计约束见仓库 AGENTS.md §3)
|
||||
mytoolkit init paper <dir> # 新建论文项目(elsarticle 脚手架,xelatex,可移植;精确配置见生成的 main.tex 头部注释,设计约束见仓库 AGENTS.md §4)
|
||||
mytoolkit init manual <dir> # 新建手册项目(技术与使用文档;与 md-to-pdf/manual Typst 模板同一视觉风格,ctexart + xelatex)
|
||||
mytoolkit init journal # 列出投稿套件
|
||||
mytoolkit init journal elsevier # Elsevier / ieee / springer 套件 → ./submit-<name>/
|
||||
```
|
||||
|
||||
投稿套件自带文档类与 bst,`make`(pdflatex+bibtex)直接编译;自动复用当前目录 `references.bib`。Springer 切样式只改 `\documentclass[...,sn-xxx]{sn-jnl}` 选项,勿写 `\bibliographystyle`。详见 AGENTS.md §3。
|
||||
投稿套件自带文档类与 bst,`make`(pdflatex+bibtex)直接编译;自动复用当前目录 `references.bib`。Springer 切样式只改 `\documentclass[...,sn-xxx]{sn-jnl}` 选项,勿写 `\bibliographystyle`。详见 AGENTS.md §4。
|
||||
|
||||
### PDF 命名约定
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
```bash
|
||||
mytoolkit init paper <dir> # 初始化 LaTeX 论文项目
|
||||
mytoolkit init manual <dir> # 初始化 LaTeX 手册项目(技术与使用文档)
|
||||
mytoolkit env # 环境变量管理
|
||||
mytoolkit git # Git 辅助工具
|
||||
mytoolkit ssh # SSH 快捷连接
|
||||
|
||||
@@ -79,7 +79,9 @@ mytoolkit voice tts "文本" -v zh_male_wennuanahu_moon_bigtts --format mp3 --sp
|
||||
|
||||
---
|
||||
|
||||
## 4. LaTeX 论文脚手架与投稿模板
|
||||
## 4. LaTeX 脚手架与投稿模板
|
||||
|
||||
模板三分法(按用途,勿混放):`templates/`(convert 转换模板,md 为源)/ `scaffolds/`(init 项目脚手架,LaTeX 源工程)/ `journals/`(init journal 投稿套件,自包含)。
|
||||
|
||||
### 新建论文项目
|
||||
|
||||
@@ -94,6 +96,14 @@ mytoolkit init paper <dir> # 默认 Elsevier elsarticle 模板(全平
|
||||
- 统一 **xelatex** 一个引擎(latexmk 驱动),便于后续加中文/系统字体;
|
||||
- `make` 编译、`make highlighted OLDTEX=...` 出 latexdiff 修订稿;`diffpreamble.dtx` 标记增删。
|
||||
|
||||
### 新建手册项目(技术与使用文档)
|
||||
|
||||
```bash
|
||||
mytoolkit init manual <dir> # LaTeX 手册模板(ctexart,xelatex)
|
||||
```
|
||||
|
||||
与 Typst `md-to-pdf/manual` 模板同一视觉风格(封面 + 目录 + 彩色标题 + 四色提示框 + 代码高亮 + 三线表),**配色与版式改动须两个模板同步**。生成 `main.tex`/`Makefile`/`README.md`;字体走 ctex 自动字体集,不写死系统字体。
|
||||
|
||||
### 切换投稿期刊模板
|
||||
|
||||
各出版社“投稿套件”预置在包内 `mytoolkit/journals/`,一条命令落地到子目录,自包含、`make` 直接编译(pdflatex + bibtex):
|
||||
|
||||
@@ -49,7 +49,7 @@ mytoolkit --help
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `convert` | Universal format conversion (md/img/pdf/eps/avi/bib → pdf/docx/tiff/mp4/md). Auto-detects from extensions. |
|
||||
| `init` | Initialize projects/kits from bundled templates (`mytoolkit init paper <dir>`, `mytoolkit init journal <name>`) |
|
||||
| `init` | Initialize projects/kits from bundled templates (`mytoolkit init paper|manual <dir>`, `mytoolkit init journal <name>`) |
|
||||
| `info` | Show bundled resource paths (`info paths`, `info docs <name>`) |
|
||||
| `pdf` | `compress` / `crop` / `merge` / `bookmark` / `to-tiff` |
|
||||
| `image` | `compress` / `eps-fix` / `eps-to-pdf` / `jpg-to-pdf` / `tiff-to-pdf` / `tiff-compress` / `generate` (Doubao/Seedream) |
|
||||
@@ -92,9 +92,11 @@ Registry is stored at `~/.mytoolkit/templates.json` (or `$MYTOOLKIT_HOME/templat
|
||||
|
||||
```bash
|
||||
mytoolkit init paper <dir> # create a LaTeX paper project (Elsevier elsarticle, xelatex, fully portable)
|
||||
mytoolkit init manual <dir> # create a LaTeX manual project (technical/user docs, same style as md-to-pdf/manual)
|
||||
```
|
||||
|
||||
This generates `main.tex`, `Makefile`, `references.bib`, `diffpreamble.dtx`, `figs/`.
|
||||
`init paper` generates `main.tex`, `Makefile`, `references.bib`, `diffpreamble.dtx`, `figs/`.
|
||||
`init manual` generates `main.tex` (cover + TOC + callout boxes + code listing + three-line tables), `Makefile`, `README.md`.
|
||||
|
||||
### Journal submission kits
|
||||
|
||||
|
||||
@@ -39,14 +39,11 @@ def init_cmd():
|
||||
pass
|
||||
|
||||
|
||||
@init_cmd.command("paper")
|
||||
@click.argument("target", type=click.Path(file_okay=False, dir_okay=True, path_type=Path))
|
||||
@handle_errors
|
||||
def init_paper(target: Path):
|
||||
"""Initialize a LaTeX paper project in TARGET directory."""
|
||||
with _scaffold_path("paper") as scaffold:
|
||||
def _init_scaffold(name: str, target: Path) -> None:
|
||||
"""Copy the bundled scaffold NAME into TARGET (must be empty or absent)."""
|
||||
with _scaffold_path(name) as scaffold:
|
||||
if not scaffold.is_dir():
|
||||
raise RuntimeError(f"Paper scaffold not found: {scaffold}")
|
||||
raise RuntimeError(f"Scaffold not found: {scaffold}")
|
||||
|
||||
if target.exists():
|
||||
if any(target.iterdir()):
|
||||
@@ -58,7 +55,7 @@ def init_paper(target: Path):
|
||||
|
||||
created = sorted(p.relative_to(target) for p in target.rglob("*") if p.is_file())
|
||||
|
||||
click.secho(f"Initialized paper project at {target}", fg="green")
|
||||
click.secho(f"Initialized {name} project at {target}", fg="green")
|
||||
for path in created:
|
||||
click.echo(f" {path}")
|
||||
|
||||
@@ -67,6 +64,22 @@ def init_paper(target: Path):
|
||||
click.echo(" make")
|
||||
|
||||
|
||||
@init_cmd.command("paper")
|
||||
@click.argument("target", type=click.Path(file_okay=False, dir_okay=True, path_type=Path))
|
||||
@handle_errors
|
||||
def init_paper(target: Path):
|
||||
"""Initialize a LaTeX paper project in TARGET directory."""
|
||||
_init_scaffold("paper", target)
|
||||
|
||||
|
||||
@init_cmd.command("manual")
|
||||
@click.argument("target", type=click.Path(file_okay=False, dir_okay=True, path_type=Path))
|
||||
@handle_errors
|
||||
def init_manual(target: Path):
|
||||
"""Initialize a LaTeX manual (technical/user doc) project in TARGET."""
|
||||
_init_scaffold("manual", target)
|
||||
|
||||
|
||||
@init_cmd.command("journal")
|
||||
@click.argument("name", type=click.Choice(sorted(JOURNALS)), required=False)
|
||||
@click.argument("target", type=click.Path(file_okay=False, dir_okay=True, path_type=Path), required=False)
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
.PHONY: all clean show-errors show-log watch help
|
||||
|
||||
TEXFILE ?= $(if $(wildcard main.tex),main.tex,$(firstword $(filter-out highlighted.tex old.tex,$(wildcard *.tex))))
|
||||
PROJECT = $(basename $(TEXFILE))
|
||||
LATEXMK = latexmk
|
||||
OUTDIR = build
|
||||
MAKELOG = $(OUTDIR)/make.log
|
||||
TEXLOG = $(OUTDIR)/$(PROJECT).log
|
||||
ARTIFACTS = $(PROJECT).aux $(PROJECT).bbl $(PROJECT).blg $(PROJECT).log $(PROJECT).out \
|
||||
$(PROJECT).toc $(PROJECT).synctex.gz $(PROJECT).fls $(PROJECT).fdb_latexmk $(PROJECT).xdv $(PROJECT).spl
|
||||
|
||||
all:
|
||||
@mkdir -p $(OUTDIR)
|
||||
@echo "Compiling $(PROJECT).tex (xelatex, full log: $(MAKELOG))..."
|
||||
@$(LATEXMK) -xelatex -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex < /dev/null > $(MAKELOG) 2>&1; \
|
||||
status=$$?; \
|
||||
if [ $$status -ne 0 ]; then \
|
||||
echo "Build failed."; \
|
||||
$(MAKE) -s show-errors; \
|
||||
echo "Full log: $(MAKELOG)"; \
|
||||
exit $$status; \
|
||||
fi
|
||||
@cp $(OUTDIR)/$(PROJECT).pdf ./$(PROJECT).pdf
|
||||
@rm -f $(ARTIFACTS)
|
||||
@echo "Done: $(PROJECT).pdf"
|
||||
|
||||
show-errors:
|
||||
@if [ -f $(TEXLOG) ]; then \
|
||||
grep -E -A2 '^! |^l\.[0-9]+ |LaTeX Error|Undefined control sequence|Missing \$$ inserted|Package .* Error|Emergency stop|Fatal error' \
|
||||
$(TEXLOG) 2>/dev/null \
|
||||
|| tail -30 $(MAKELOG); \
|
||||
else \
|
||||
tail -30 $(MAKELOG); \
|
||||
fi
|
||||
|
||||
show-log:
|
||||
@less $(MAKELOG)
|
||||
|
||||
clean:
|
||||
$(LATEXMK) -C -outdir=$(OUTDIR) $(PROJECT).tex
|
||||
rm -rf $(OUTDIR)
|
||||
rm -f $(ARTIFACTS)
|
||||
|
||||
watch:
|
||||
$(LATEXMK) -pvc -xelatex -outdir=$(OUTDIR) -interaction=nonstopmode $(PROJECT).tex
|
||||
|
||||
help:
|
||||
@echo
|
||||
@echo '1. "make" compile (latexmk, output in build/, PDF copied to root; on error prints the failing lines and stops)'
|
||||
@echo '2. "make show-errors" re-print the error lines from the last build'
|
||||
@echo '3. "make show-log" page through the full build log'
|
||||
@echo '4. "make watch" continuous preview-compile (latexmk -pvc)'
|
||||
@echo '5. "make clean" remove build/ and stray artifacts'
|
||||
@echo
|
||||
@@ -0,0 +1,38 @@
|
||||
# Manual Project
|
||||
|
||||
This project was initialized with `mytoolkit init manual`. It is a LaTeX
|
||||
manual template (technical & user documentation) with the same visual style as
|
||||
the Typst `md-to-pdf/manual` template: cover page, TOC, colored headings,
|
||||
callout boxes, code listings, and three-line tables. Compiles with `xelatex`
|
||||
via `latexmk`; CJK fonts are resolved by `ctex` automatically.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
- `main.tex`: main document (cover, styles, demo content — replace with yours)
|
||||
- `Makefile`: build script
|
||||
- `build/`: build output (auto-generated)
|
||||
|
||||
## Build
|
||||
|
||||
```bash
|
||||
make
|
||||
```
|
||||
|
||||
A successful build produces `main.pdf`.
|
||||
|
||||
## Callout Boxes
|
||||
|
||||
Four colored boxes are predefined (optional argument overrides the title):
|
||||
|
||||
```latex
|
||||
\begin{infobox}[自定义标题] ... \end{infobox}
|
||||
\begin{tipbox} ... \end{tipbox}
|
||||
\begin{warnbox} ... \end{warnbox}
|
||||
\begin{dangerbox} ... \end{dangerbox}
|
||||
```
|
||||
|
||||
## Other Commands
|
||||
|
||||
- `make clean`: remove build artifacts
|
||||
- `make watch`: continuous preview compilation
|
||||
- `make show-errors`: show the most recent build errors
|
||||
@@ -0,0 +1,227 @@
|
||||
%% Manual template (technical & user documentation).
|
||||
%% Same visual style as the Typst md-to-pdf/manual template:
|
||||
%% cover page + TOC + colored headings + callout boxes + code listing + three-line tables.
|
||||
%% Engine: xelatex (via latexmk); CJK fonts resolved by ctex automatically (portable).
|
||||
\documentclass[UTF8,10pt]{ctexart}
|
||||
|
||||
\usepackage[a4paper,margin=2cm]{geometry}
|
||||
\usepackage{xcolor}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{booktabs}
|
||||
\usepackage{colortbl}
|
||||
\usepackage{listings}
|
||||
\usepackage[most]{tcolorbox}
|
||||
\usepackage{titlesec}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{hyperref}
|
||||
|
||||
% ---- palette (keep in sync with templates/md-to-pdf/manual/template.typ) ----
|
||||
\definecolor{primary}{HTML}{1F4E79}
|
||||
\definecolor{secondary}{HTML}{2C3E50}
|
||||
\definecolor{accent}{HTML}{3467A8}
|
||||
\definecolor{light}{HTML}{96A0AA}
|
||||
\colorlet{ruleblue}{accent!46!white}
|
||||
|
||||
\definecolor{infocolor}{HTML}{0EA5E9}
|
||||
\definecolor{tipcolor}{HTML}{10B981}
|
||||
\definecolor{warncolor}{HTML}{F59E0B}
|
||||
\definecolor{dangercolor}{HTML}{EF4444}
|
||||
|
||||
\definecolor{codebg}{HTML}{F8F9FA}
|
||||
\definecolor{codenum}{HTML}{6E7681}
|
||||
|
||||
\hypersetup{colorlinks=true, linkcolor=accent, urlcolor=accent, citecolor=accent,
|
||||
bookmarksopen=true, bookmarksopenlevel=2}
|
||||
|
||||
% ---- headings (numbered; add \setcounter{secnumdepth}{-2} to go unnumbered) ----
|
||||
\setcounter{tocdepth}{2}
|
||||
\titleformat{\section}{\fontsize{18}{22}\selectfont\bfseries\color{primary}}
|
||||
{\thesection}{0.6em}{}
|
||||
\titlespacing*{\section}{0pt}{1.45em plus 4pt}{0.55em}
|
||||
\titleformat{\subsection}{\fontsize{13}{16}\selectfont\bfseries\color{accent}}
|
||||
{\thesubsection}{0.6em}{}
|
||||
\titlespacing*{\subsection}{0pt}{1.1em plus 3pt}{0.5em}
|
||||
\titleformat{\subsubsection}{\fontsize{11}{14}\selectfont\bfseries\color{secondary}}
|
||||
{\thesubsubsection}{0.6em}{}
|
||||
\titlespacing*{\subsubsection}{0pt}{0.8em plus 2pt}{0.4em}
|
||||
|
||||
% ---- header: current section (right); footer: page number (center) ----
|
||||
\pagestyle{fancy}
|
||||
\fancyhf{}
|
||||
\setlength{\headheight}{14pt}
|
||||
\renewcommand{\headrulewidth}{0pt}
|
||||
\renewcommand{\sectionmark}[1]{\markright{#1}}
|
||||
\fancyhead[R]{\fontsize{8}{10}\selectfont\color{light}\rightmark}
|
||||
\fancyfoot[C]{\fontsize{8}{10}\selectfont\color{light}--- \thepage\ ---}
|
||||
|
||||
% ---- compact lists ----
|
||||
\setlist{nosep, leftmargin=1.8em}
|
||||
|
||||
% ---- three-line tables: \toprule / \midrule / \bottomrule ----
|
||||
\arrayrulecolor{ruleblue}
|
||||
|
||||
% ---- code listing (rounded corners need tcolorbox; plain frame keeps it light) ----
|
||||
\lstset{
|
||||
basicstyle=\ttfamily\small,
|
||||
backgroundcolor=\color{codebg},
|
||||
frame=single, framerule=0.5pt, rulecolor=\color{ruleblue},
|
||||
framesep=3pt, xleftmargin=2em,
|
||||
numbers=left, numberstyle=\tiny\color{codenum}, numbersep=8pt,
|
||||
breaklines=true, columns=fullflexible, keepspaces=true,
|
||||
showstringspaces=false,
|
||||
keywordstyle=\color{accent}\bfseries,
|
||||
commentstyle=\color{light}\itshape,
|
||||
stringstyle=\color{tipcolor},
|
||||
}
|
||||
|
||||
% ---- callout boxes: title bar colored, body white (mirrors Typst showybox) ----
|
||||
\newtcolorbox{infobox}[1][信息]{enhanced, breakable,
|
||||
colback=white, colframe=infocolor, colbacktitle=infocolor, coltitle=white,
|
||||
fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm,
|
||||
left=2mm, right=2mm, top=1.5mm, bottom=1.5mm}
|
||||
\newtcolorbox{tipbox}[1][提示]{enhanced, breakable,
|
||||
colback=white, colframe=tipcolor, colbacktitle=tipcolor, coltitle=white,
|
||||
fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm,
|
||||
left=2mm, right=2mm, top=1.5mm, bottom=1.5mm}
|
||||
\newtcolorbox{warnbox}[1][注意]{enhanced, breakable,
|
||||
colback=white, colframe=warncolor, colbacktitle=warncolor, coltitle=white,
|
||||
fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm,
|
||||
left=2mm, right=2mm, top=1.5mm, bottom=1.5mm}
|
||||
\newtcolorbox{dangerbox}[1][危险]{enhanced, breakable,
|
||||
colback=white, colframe=dangercolor, colbacktitle=dangercolor, coltitle=white,
|
||||
fonttitle=\bfseries, title={#1}, boxrule=1pt, arc=2mm,
|
||||
left=2mm, right=2mm, top=1.5mm, bottom=1.5mm}
|
||||
|
||||
\begin{document}
|
||||
|
||||
% ---- cover page ----
|
||||
\begin{titlepage}
|
||||
\centering
|
||||
\vspace*{2cm}
|
||||
{\fontsize{28}{34}\selectfont\bfseries\color{primary} Phynexis Python API 参考手册\par}
|
||||
\vspace{0.8cm}
|
||||
{\fontsize{16}{20}\selectfont\color{accent} 技术与使用文档\par}
|
||||
\vspace{2cm}
|
||||
{\fontsize{12}{16}\selectfont\color{light} 2026 年 7 月\par}
|
||||
\vfill
|
||||
\end{titlepage}
|
||||
|
||||
\tableofcontents
|
||||
\newpage
|
||||
|
||||
\section{快速开始}
|
||||
|
||||
\subsection{安装}
|
||||
|
||||
通过 pip 安装 Phynexis:
|
||||
|
||||
\begin{lstlisting}[language=bash]
|
||||
pip install phynexis
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{tipbox}[提示]
|
||||
建议使用虚拟环境安装,避免与系统 Python 包冲突:
|
||||
|
||||
\begin{lstlisting}[language=bash]
|
||||
python -m venv venv
|
||||
source venv/bin/activate # Linux/macOS
|
||||
\end{lstlisting}
|
||||
\end{tipbox}
|
||||
|
||||
\subsection{第一个示例}
|
||||
|
||||
\begin{lstlisting}[language=Python]
|
||||
from phynexis import Model, Mesh
|
||||
|
||||
# 创建简单网格
|
||||
mesh = Mesh.rectangle(width=1.0, height=1.0, nx=20, ny=20)
|
||||
|
||||
# 定义材料模型并求解
|
||||
model = Model(mesh)
|
||||
model.set_material(young=210e9, nu=0.3, rho=7850)
|
||||
result = model.solve()
|
||||
print(f"最大位移: {result.max_displacement:.6f} m")
|
||||
\end{lstlisting}
|
||||
|
||||
\section{核心 API}
|
||||
|
||||
\subsection{Mesh 类}
|
||||
|
||||
网格是有限元分析的基础。\lstinline|Mesh| 类提供多种工厂方法创建常见几何。
|
||||
|
||||
\begin{infobox}[\lstinline|Mesh.rectangle|]
|
||||
\textbf{签名}: \lstinline|Mesh.rectangle(width, height, nx, ny)|
|
||||
|
||||
\textbf{参数}:
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{lll}
|
||||
\toprule
|
||||
参数 & 类型 & 说明 \\
|
||||
\midrule
|
||||
\lstinline|width| & float & 矩形宽度 \\
|
||||
\lstinline|height| & float & 矩形高度 \\
|
||||
\lstinline|nx| & int & x 方向单元数 \\
|
||||
\lstinline|ny| & int & y 方向单元数 \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\textbf{返回}: \lstinline|Mesh| 实例
|
||||
\end{infobox}
|
||||
|
||||
\subsection{Model 类}
|
||||
|
||||
\lstinline|Model| 封装了物理场求解的完整流程:
|
||||
|
||||
\begin{lstlisting}[language=Python]
|
||||
model = Model(mesh)
|
||||
model.set_material(young=210e9, nu=0.3)
|
||||
model.fix_boundary(tag="left") # 固定左侧边界
|
||||
model.apply_force(tag="right", fx=1e6) # 右侧施加力
|
||||
result = model.solve(solver="direct")
|
||||
\end{lstlisting}
|
||||
|
||||
\begin{warnbox}[注意]
|
||||
\lstinline|solve()| 默认使用直接求解器。大规模问题(> 100,000 DOF)建议改用迭代求解器:
|
||||
|
||||
\begin{lstlisting}[language=Python]
|
||||
result = model.solve(solver="cg", preconditioner="ilu")
|
||||
\end{lstlisting}
|
||||
\end{warnbox}
|
||||
|
||||
\section{高级用法}
|
||||
|
||||
\subsection{并行计算}
|
||||
|
||||
\begin{dangerbox}[危险]
|
||||
在并行环境内分配数组时,务必确保每个进程只分配自己的局部部分。全局数组会导致内存溢出:
|
||||
|
||||
\begin{lstlisting}[language=Python]
|
||||
local_K = np.zeros((n_local, n_local)) # 正确:只分配局部矩阵
|
||||
\end{lstlisting}
|
||||
\end{dangerbox}
|
||||
|
||||
\section{故障排除}
|
||||
|
||||
\textbf{Q: 求解器收敛失败}
|
||||
|
||||
检查以下事项:
|
||||
|
||||
\begin{enumerate}
|
||||
\item 边界条件是否充分约束了刚体位移
|
||||
\item 材料参数是否合理(特别是泊松比接近 0.5 时)
|
||||
\item 网格质量是否太差
|
||||
\end{enumerate}
|
||||
|
||||
\section{版本历史}
|
||||
|
||||
\subsection{v2.1.0 (2026-05-01)}
|
||||
|
||||
\begin{itemize}
|
||||
\item 新增 GPU 加速求解器(CUDA 后端)
|
||||
\item 支持非线性材料模型
|
||||
\end{itemize}
|
||||
|
||||
\end{document}
|
||||
Reference in New Issue
Block a user