json-fortran库的使用
本次推文介绍json-fortran
库的使用。在使用fortran进行有限元编程的过程中,为了更加灵活的进行模型参数修改,可以采用配置文件的方法。
我采用的是json配置文件,可以直接将数据返回为结构体,便于程序内部的引用。但是Fortran并没有像matlab、Python那样天然对各种库的支持,很多情况下需要自己去编写各种功能子程序。
对于json数据的抓取,固然可以自己写一个模块对自己的数据进行自定义抓取,但是无疑会增加很多代码量,可以采用已有编译好的库,直接引用就行,现在就来介绍json-fortran
库的使用方法。
项目地址:https://github.com/jacobwilliams/json-fortran
编译方法
下载整个项目文件即可,需要自己先编译一遍,方法有很多,我一贯使用的是gfortran(MinGW)。
首先要安装 Ninja.exe(https://github.com/ninja-build/ninja/releases)
在下载好的json-fortran文件夹中进入命令行:
mkdir build && cd build
cmake -G "Ninja" -DCMAKE_Fortran_COMPILER=gfortran -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="C:/jsonfortran" ..
cmake --build . --config Release
cmake --install .
安装后你会得到:
将这个lib文件夹复制到你的fortran项目目录中,我复制在主目录的package文件夹的json-fortran中,然后可以在makefile中这样配置:
# 主程序名称(不带后缀)
MAIN := main# 产出目录
BUILDDIR := build
MODDIR := mod# 对象文件
OBJ := $(BUILDDIR)/main.oFC := gfortran
FCFLAGS := -O3 -march=nativeJSON_DIR := package/json-fortran/lib
JSON_STATIC := $(JSON_DIR)/libjsonfortran.a# 确保目录存在
$(BUILDDIR) $(MODDIR):@if not exist "$@" mkdir "$@"# 链接
$(MAIN): $(OBJ)$(FC) $(FCFLAGS) -I$(JSON_DIR) -J$(MODDIR) $(OBJ) \$(JSON_STATIC) -static-libgfortran -static-libgcc \-o $@# 编译
$(BUILDDIR)/%.o: %.f90 | $(BUILDDIR) $(MODDIR)$(FC) $(FCFLAGS) -I$(JSON_DIR) -J$(MODDIR) -c $< -o $@.PHONY: clean run
clean:@echo Cleaning only $(BUILDDIR)/, $(MODDIR)/ and top-level artifacts...@if exist "$(BUILDDIR)" rmdir /S /Q "$(BUILDDIR)"@if exist "$(MODDIR)" rmdir /S /Q "$(MODDIR)"@if exist "$(MAIN).exe" del /Q "$(MAIN).exe"@del /Q *.o 2>nul@del /Q *.mod 2>nul@del /Q $(MAIN) 2>nul && remrun: $(MAIN).\$(MAIN)
在这里我的主程序名字为main.f90,在makefile中不用带后缀名,目标文件.o
全部存放在build目录下,mod
文件全部放在mod文件夹下,然后直接在终端进行make
就直接编译,设计的make clean
规则可以清除主目录、build、mod目录下的编译文件,保证package目录下的mod文件不被清除。
使用json-fortran
经过上述操作已经可以使用该库了,来一个测试程序:
program mainuse json_moduleuse iso_fortran_env, only: real64implicit nonetype(json_file) :: jflogical :: ok, binteger :: nreal(real64) :: tolcharacter(len=:), allocatable :: scall jf%load_file("solid.json")call jf%get("name", s, ok); if (ok) print *, "name =", trim(s)call jf%get("mesh.etype", s, ok); if (ok) print *, "etype =", trim(s)call jf%get("plot.edgeColor", s, ok); if (ok) print *, "edgeColor =", trim(s)call jf%get("plot.fields(1)", s, ok); if (ok) print *, "fields(1) =", trim(s)call jf%get("solve.solver", s, ok); if (ok) print *, "solver =", trim(s)call jf%get("solve.tolerance", tol, ok); if (ok) print *, "tol =", tolcall jf%get("solve.maxIterations", n, ok); if (ok) print *, "maxIt =", ncall jf%get("solve.calculateStress", b, ok); if (ok) print *, "calcStress =", b! 数组里的对象:call jf%get("materials(1).name", s, ok); if (ok) print *, "mat1.name =", trim(s)call jf%get("materials(1).data.E", tol, ok); if (ok) print *, "mat1.E =", tolcall jf%get("bc(2).type", s, ok); if (ok) print *, "bc2.type =", trim(s)call jf%get("bc(2).surface", s, ok); if (ok) print *, "bc2.surface =", trim(s)call jf%get("bc(2).value", tol, ok); if (ok) print *, "bc2.value =", tolcall jf%destroy()
end program main
json文件为:
{"name": "C3D4test2","scale": 1,"inpFileName" : "./input/Abaqus/C3D4test2.inp","mesh" :{"etype" : "C3D4"},"materials" : [{"name" : "Material-1","category" : "Elastic","data" : {"E" : 70000,"v" : 0.3}}],"bc" : [{"name" : "fix1","type": "constraint","direction": "xyz","nset" : "BoltBC"},{"name" : "Surf-5", "type": "pressure", "surface" : "Surf-5", "value" : 100},{"name" : "Surf-6", "type": "pressure", "surface" : "Surf-6", "value" : 100},{"name" : "Surf-7", "type": "pressure", "surface" : "Surf-7", "value" : 100},{"name" : "Surf-8", "type": "pressure", "surface" : "Surf-8", "value" : 100}],"solve" : {"calculateStress": false,"solver" : "pcg","tolerance": 1e-8,"maxIterations": 1000},"plot" : {"fields" : ["Umag"],"average" : "simple","edgeColor" : "#000080","faceColor" : "#77AC30","alpha" : 1,"nodeLabel" : false,"colorMap" : "coolwarm","discretize" : true,"discretizeNum" : 12}
}
输出:
name =C3D4test2etype =C3D4edgeColor =#000080fields(1) =Umagsolver =pcgtol = 1.0000000000000000E-008maxIt = 1000calcStress = Fmat1.name =Material-1mat1.E = 70000.000000000000bc2.type =pressurebc2.surface =Surf-5bc2.value = 100.00000000000000
这样一来,每次只需在程序中使用call jf%get
即可引用相应的值。