本次推文将为大家简要介绍toml配置文件,在之前木木一直用的json文件作为有限元程序的配置文件,这几天的上网冲浪中发现了更好用的配置文件语言—toml。
有关toml的介绍,详看:https://toml.io/cn/v1.0.0,这里简要介绍与json相比,toml的优势:
# 这是配置文件的标题
title = "My Configuration"
# 数据库配置
[database]
server = "192.168.1.1" # 数据库地址
# toml
title = "Example Config"
[database]
server = "192.168.1.1"
ports = [ 8000, 8001, 8002 ]
# json
{
"title": "Example Config",
"database": {
"server": "192.168.1.1",
"ports": [8000, 8001, 8002]
}
}
# toml
[server]
ip = "127.0.0.1"
port = 8080
[[users]]
name = "Alice"
age = 30
[[users]]
name = "Bob"
age = 25
# json
{
"server": {
"ip": "127.0.0.1",
"port": 8080
},
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]
}
这里给出一份有限元程序的配置文件,试用python和matlab两种语言分别解析。
title = "Job-1"
parameter_filename = "parameters.toml"
[mesh]
type = "gmsh"
file = 'rectangle100.msh'
[dof]
names = ["u1", "u2"]
order = 1
family = "LAGRANGE"
[[amplitudes]]
name = "Amp-1"
type = "TabularAmplitude"
start = 0.0
data = [
[0.0, 0.0],
[0.5, 1.0],
[1.0, 0.0],
[1.5, -1.0],
[2.0, 0.0],
[2.5, 1.0],
[3.0, 0.0],
[3.5, -1.0],
[4.0, 0.0],
[4.5, 1.0],
[5.0, 0.0],
]
[[bcs]]
name = "BC-1"
category = "DirichletBC"
type = ""
dof = ["u2"]
node_sets = ['bottom']
element_sets = []
value = 0.0
[[bcs]]
name = "BC-2"
category = "DirichletBC"
type = ""
dof = ["u2"]
node_sets = ['top']
element_sets = []
value = 0.01
amplitude_name = "Amp-1"
[[bcs]]
name = "BC-3"
category = "NeumannBC"
type = "Distributed"
dof = ["u1"]
node_sets = []
bc_element_sets = ['right']
value = 500.0
[solver]
type = "LinearSolver"
option = "NewtonRaphson"
total_time = 1.0
start_time = 0.0
max_increment = 1000000
initial_dtime = 0.05
max_dtime = 0.05
min_dtime = 0.001
[[materials]]
name = "Material-1"
category = "Elastic"
type = "Isotropic"
data = [3e11, 0.25] # Young's modulus, Poisson's ratio
[[sections]]
name = "Section-1"
category = "Solid"
type = "PlaneStrain"
option = "SmallStrain"
element_sets = ["rectangle"]
material_names = ["Material-1"]
data = []
[[outputs]]
type = "vtk"
field_outputs = ['S11', 'S22', 'S12', 'E11', 'E22', 'E12']
is_save = true
tomllib是Python 3.11中引入的标准库模块,用于解析TOML文件。如果你使用的是Python 3.11或更高版本,则不需要安装tomllib,因为它已经包含在标准库中。
如果你使用的是Python 3.11以下的版本,就需要pip install toml
。
有关两者的联用的方式,可详看:《Python和TOML:新的好朋友》(https://cn.python-3.com/?p=133)
import tomllib
# 读取 TOML 文件
with open("config.toml", "rb") as file:
config = tomllib.load(file)
# 逐步解析和打印各部分内容
# 标题和主配置
print("Title:", config["title"])
print("Parameter Filename:", config["parameter_filename"])
# 网格配置
print("\n[Mesh]")
print("Type:", config["mesh"]["type"])
print("File:", config["mesh"]["file"])
# 自由度 (Degrees of Freedom, DOF)
print("\n[DOF]")
print("Names:", config["dof"]["names"])
print("Order:", config["dof"]["order"])
print("Family:", config["dof"]["family"])
# 振幅配置
print("\n[Amplitudes]")
for amplitude in config["amplitudes"]:
print("Name:", amplitude["name"])
print("Type:", amplitude["type"])
print("Start:", amplitude["start"])
print("Data:", amplitude["data"])
# 边界条件 (Boundary Conditions)
print("\n[Boundary Conditions (BCs)]")
for bc in config["bcs"]:
print("Name:", bc["name"])
print("Category:", bc["category"])
print("Type:", bc["type"])
print("DOF:", bc["dof"])
print("Node Sets:", bc.get("node_sets", [])) # 使用 get 方法
print("Element Sets:", bc.get("element_sets", [])) # 使用 get 方法
print("Value:", bc["value"])
if "amplitude_name" in bc:
print("Amplitude Name:", bc["amplitude_name"])
# 求解器配置
print("\n[Solver]")
solver = config["solver"]
print("Type:", solver["type"])
print("Option:", solver["option"])
print("Total Time:", solver["total_time"])
print("Start Time:", solver["start_time"])
print("Max Increment:", solver["max_increment"])
print("Initial Time Step:", solver["initial_dtime"])
print("Max Time Step:", solver["max_dtime"])
print("Min Time Step:", solver["min_dtime"])
# 材料配置
print("\n[Materials]")
for material in config["materials"]:
print("Name:", material["name"])
print("Category:", material["category"])
print("Type:", material["type"])
print("Data:", material["data"])
# 截面配置
print("\n[Sections]")
for section in config["sections"]:
print("Name:", section["name"])
print("Category:", section["category"])
print("Type:", section["type"])
print("Option:", section["option"])
print("Element Sets:", section["element_sets"])
print("Material Names:", section["material_names"])
print("Data:", section["data"])
# 输出配置
print("\n[Outputs]")
for output in config["outputs"]:
print("Type:", output["type"])
print("Field Outputs:", output["field_outputs"])
print("Is Save:", output["is_save"])
matlab并不原生支持解析toml,可参照github:https://github.com/g-s-k/matlab-toml,将其添加到路径中进行解析。
% 清理工作空间
clc; clear;
% 读取 TOML 文件
config = toml.read('config.toml');
% 转换为结构体
config = toml.map_to_struct(config);
% 示例:逐步解析和打印各部分内容
% 标题和主配置
disp("Title: " + config.title);
disp("Parameter Filename: " + config.parameter_filename);
% 网格配置
disp(newline + "[Mesh]");
disp("Type: " + config.mesh.type);
disp("File: " + config.mesh.file);
% 自由度 (Degrees of Freedom, DOF)
disp(newline + "[DOF]");
disp("Names: " + strjoin(config.dof.names, ", "));
disp("Order: " + config.dof.order);
disp("Family: " + config.dof.family);
% 振幅配置
disp(newline + "[Amplitudes]");
for i = 1:numel(config.amplitudes)
amplitude = config.amplitudes{i};
disp("Name: " + amplitude.name);
disp("Type: " + amplitude.type);
disp("Start: " + amplitude.start);
disp("Data: ");
disp(amplitude.data);
end
% 边界条件 (Boundary Conditions)
disp(newline + "[Boundary Conditions (BCs)]");
for i = 1:numel(config.bcs)
bc = config.bcs{i};
disp("Name: " + bc.name);
disp("Category: " + bc.category);
disp("Type: " + bc.type);
disp("DOF: " + strjoin(bc.dof, ", "));
disp("Node Sets: " + strjoin(bc.node_sets, ", "));
% 检查 element_sets 是否存在
if isfield(bc, "element_sets")
disp("Element Sets: " + strjoin(bc.element_sets, ", "));
else
disp("Element Sets: [Not Defined]");
end
disp("Value: " + bc.value);
% 检查 amplitude_name 是否存在
if isfield(bc, "amplitude_name")
disp("Amplitude Name: " + bc.amplitude_name);
end
end
% 求解器配置
disp(newline + "[Solver]");
solver = config.solver;
disp("Type: " + solver.type);
disp("Option: " + solver.option);
disp("Total Time: " + solver.total_time);
disp("Start Time: " + solver.start_time);
disp("Max Increment: " + solver.max_increment);
disp("Initial Time Step: " + solver.initial_dtime);
disp("Max Time Step: " + solver.max_dtime);
disp("Min Time Step: " + solver.min_dtime);
% 材料配置
disp(newline + "[Materials]");
for i = 1:numel(config.materials)
material = config.materials{i};
disp("Name: " + material.name);
disp("Category: " + material.category);
disp("Type: " + material.type);
disp("Data: " + mat2str(material.data));
end
% 截面配置
disp(newline + "[Sections]");
for i = 1:numel(config.sections)
section = config.sections{i};
disp("Name: " + section.name);
disp("Category: " + section.category);
disp("Type: " + section.type);
disp("Option: " + section.option);
disp("Element Sets: " + strjoin(section.element_sets, ", "));
disp("Material Names: " + strjoin(section.material_names, ", "));
% 检查 data 是否为空或者类型不匹配
if isempty(section.data)
disp("Data: [Empty]");
elseif isnumeric(section.data) || iscell(section.data)
disp("Data: " + mat2str(section.data));
else
disp("Data: [Unsupported Format]");
end
end
% 输出配置
disp(newline + "[Outputs]");
for i = 1:numel(config.outputs)
output = config.outputs{i};
disp("Type: " + output.type);
disp("Field Outputs: " + strjoin(output.field_outputs, ", "));
disp("Is Save: " + string(output.is_save));
end
通过toml.read
将toml文件解析为map对象,需要再次使用toml.map_to_struct
将map对象转换为结构体,这样更方便数据的调用。
MFEAOOP在转向PyMFEAOOP后将采用toml作为程序的配置文件,更多精彩内容敬请期待。