This commit is contained in:
tp 2025-05-09 14:01:19 +08:00
commit 97b97cc17a
18 changed files with 1836 additions and 0 deletions

View File

@ -0,0 +1,74 @@
using Microsoft.AspNetCore.Mvc;
using FortranWebApi.Models;
using FortranWebApi.Services;
using System.Text.Json;
namespace FortranWebApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class FortranCalculateController : ControllerBase
{
private readonly FortranInteropService _fortranService;
private readonly ILogger<FortranCalculateController> _logger;
public FortranCalculateController(FortranInteropService fortranService, ILogger<FortranCalculateController> logger)
{
_fortranService = fortranService;
_logger = logger;
}
[HttpPost]
public IActionResult Post([FromBody] FortranRequestWrapper wrapper)
{
try
{
if (string.IsNullOrEmpty(wrapper.Text))
{
return BadRequest(new
{
message = "请求文本不能为空",
success = false,
data = (object)null
});
}
string result = _fortranService.ProcessFortranRequest(wrapper.Text);
// 使用驼峰命名法解析结果
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
var resultObj = JsonSerializer.Deserialize<FortranRequest>(result, options);
// 返回新的格式
var response = new ApiResponse<FortranRequest>
{
Message = "Success",
Success = true,
Data = new ApiResponseData<FortranRequest>
{
Value = resultObj
}
};
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "处理Fortran请求时发生错误");
return StatusCode(500, new
{
message = ex.Message,
success = false,
data = (object)null
});
}
}
}
}

88
Dockerfile Normal file
View File

@ -0,0 +1,88 @@
# ===== 第一阶段:构建阶段 =====
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
# 配置 NuGet 使用国内镜像源
RUN dotnet nuget add source https://mirrors.cloud.tencent.com/nuget/ \
&& dotnet nuget disable source nuget.org
# 配置 apt-get 使用 apt-cacher-ng 作为代理
RUN echo 'Acquire::http::Proxy "http://192.168.1.140:3142";' > /etc/apt/apt.conf.d/01proxy
# 创建并配置 Debian 镜像源
RUN echo "deb https://mirrors.ustc.edu.cn/debian/ bookworm main contrib non-free non-free-firmware" > /etc/apt/sources.list && \
echo "deb https://mirrors.ustc.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb https://mirrors.ustc.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list
# 允许使用不安全的软件源
RUN echo 'Acquire::AllowInsecureRepositories "true";' > /etc/apt/apt.conf.d/99allow-insecure && \
echo 'Acquire::AllowDowngradeToInsecureRepositories "true";' >> /etc/apt/apt.conf.d/99allow-insecure
WORKDIR /src
# 安装 Fortran 编译器
RUN apt-get update && apt-get install -y --no-install-recommends \
gfortran \
&& rm -rf /var/lib/apt/lists/*
# 复制 Fortran 源文件并编译
COPY Fortran/*.f90 /src/Fortran/
WORKDIR /src/Fortran
# 编译所有 .f90 文件为 .o 文件
RUN for file in *.f90; do gfortran -fPIC -c "$file" -o "${file%.f90}.o"; done
# 链接所有 .o 文件为共享库
RUN gfortran -shared *.o -o libMSJGMX.so
# 回到主工作目录
WORKDIR /src
# 只复制项目文件
COPY ["FortranWebApi.csproj", "./"]
RUN dotnet restore
# 复制源代码
COPY . .
# 合并 build 和 publish 命令
RUN dotnet publish -c Release -o /app/publish
# 复制编译好的 .so 文件到发布目录
RUN mkdir -p /app/publish && \
cp /src/Fortran/libMSJGMX.so /app/publish/
# ===== 第二阶段:运行阶段 =====
FROM mcr.microsoft.com/dotnet/aspnet:8.0
# 配置 apt-get 使用 apt-cacher-ng 作为代理
RUN echo 'Acquire::http::Proxy "http://192.168.1.140:3142";' > /etc/apt/apt.conf.d/01proxy
# 创建并配置 Debian 镜像源
RUN echo "deb https://mirrors.ustc.edu.cn/debian/ bookworm main contrib non-free non-free-firmware" > /etc/apt/sources.list && \
echo "deb https://mirrors.ustc.edu.cn/debian/ bookworm-updates main contrib non-free non-free-firmware" >> /etc/apt/sources.list && \
echo "deb https://mirrors.ustc.edu.cn/debian-security bookworm-security main contrib non-free non-free-firmware" >> /etc/apt/sources.list
# 允许使用不安全的软件源
RUN echo 'Acquire::AllowInsecureRepositories "true";' > /etc/apt/apt.conf.d/99allow-insecure && \
echo 'Acquire::AllowDowngradeToInsecureRepositories "true";' >> /etc/apt/apt.conf.d/99allow-insecure
# 安装运行时依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
libc6-dev \
libgfortran5 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=build /app/publish .
# 确保 .so 文件的权限正确
RUN chmod 755 /app/libMSJGMX.so
# 设置 LD_LIBRARY_PATH
ENV LD_LIBRARY_PATH=/app
# 设置端口和监听地址
ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000
ENTRYPOINT ["dotnet", "FortranWebApi.dll"]

192
Fortran/1.json Normal file
View File

@ -0,0 +1,192 @@
{
"fortranSourceFile": "D:\\\u5DE5\u4F5C2025\\\u7B97\u6CD5\u5E73\u53F0\\dll\\\u9A6C\u65AF\u4EAC\u8DDF\u6A21\u578B\\MSJGMX\\MSJGMX\\MSJGMX - \u526F\u672C.f90",
"fortranFunctionName": "MSJGMX",
"projectName": "FortranWebApi",
"outputDirectory": "D:\\\u5DE5\u4F5C2025\\\u7B97\u6CD5\u5E73\u53F0\\\u8F93\u51FA\u5E93\\\u9A6C\u65AF\u4EAC\u8DDF\u6A21\u578B",
"parameters": [
{
"name": "FILELEN",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "NODE",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "M",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "PAR",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "NAREA",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "AREA",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "UH",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "DT",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "P",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "EP",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "W",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "FR",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "S",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "QRSS0",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "QRG0",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Q20",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "X",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "K",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "DETAT",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "C0",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Output",
"description": "",
"isSelected": true
},
{
"name": "C1",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Output",
"description": "",
"isSelected": true
},
{
"name": "C2",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Output",
"description": "",
"isSelected": true
},
{
"name": "QOUT",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Output",
"description": "",
"isSelected": true
}
]
}

BIN
Fortran/1.xlsx Normal file

Binary file not shown.

90
Fortran/MSJGMX.f90 Normal file
View File

@ -0,0 +1,90 @@
subroutine MSJGMX( FILELEN ,&
NODE ,& ! //
M ,& ! //
PAR ,& ! //
NAREA ,& ! //
AREA ,& ! //
UH ,& ! 线 //
DT ,& ! //
P ,& ! //
EP ,& ! //
W ,& ! 1. 2. 3. //
FR ,& ! //
S ,& ! //
QRSS0 ,& ! //
QRG0 ,& ! //
Q20 ,& ! //
X ,& ! //
K ,& ! //
DETAT ,& ! //
C0 ,& ! //
C1 ,& ! //
C2 ,& ! //
QOUT ) ! //
! Expose subroutine MSJGMX to users of this DLL
!DEC$ ATTRIBUTES DLLEXPORT::MSJGMX
IMPLICIT NONE
REAL::X
REAL::K
REAL::DETAT
REAL::C0
REAL::C1
REAL::C2
REAL::Q2(1000)
INTEGER::NFILENAME
CHARACTER(LEN = 10)::FILENAME
INTEGER:: FILELEN
INTEGER::NODE !
INTEGER::M , I !
REAL::PAR(13) ! 1.wum 2.wl 3.wdm
! 4.KC.c 6.b
! 7.imp1 8.sm 9.ex
!10.kg 11.kss 12.kkg
!13.kkss
INTEGER::NAREA !
REAL::AREA(NAREA) !
REAL::UH(M) ! 线
REAL::DT !
REAL::P(NAREA,NODE) !
REAL::EP(NAREA,NODE) !
REAL::W(3) ! 1. 2. 3.
REAL::FR !
REAL::S !
REAL::QRSS0 !
REAL::QRG0 !
REAL::Q20(NAREA)
REAL::QOUT(NAREA)
CALL XAJ( FILELEN ,&
NODE ,& ! //
M ,& ! //
PAR ,& ! //
NAREA ,& ! //
AREA ,& ! //
UH ,& ! 线 //
DT ,& ! //
P ,& ! //
EP ,& ! //
W ,& ! 1. 2. 3. //
FR ,& ! //
S ,& ! //
QRSS0 ,& ! //
QRG0 ,& ! //
Q20 ,& ! //
X ,& ! //
K ,& ! //
DETAT ,& ! //
C0 ,& ! //
C1 ,& ! //
C2 ,& ! //
QOUT ) ! //
end subroutine MSJGMX

64
Fortran/Mc_method.f90 Normal file
View File

@ -0,0 +1,64 @@
! Mc_method.f90
!
! FUNCTIONS:
! Mc_method - Entry point of console application.
!
!****************************************************************************
!
! PROGRAM: Mc_method
!
! PURPOSE: Entry point for the console application.
!
!****************************************************************************
SUBROUTINE Mc_method( NFILENAME ,& ! //
FILENAME ,& ! //
N ,& ! //
Q1 ,& ! //
Q20 ,& ! //
X ,& ! //
K ,& ! //
DETAT ,& ! //
C0 ,& ! //
C1 ,& ! //
C2 ,& ! //
Q2 ) ! //
INTEGER::NFILENAME
CHARACTER(LEN = NFILENAME)::FILENAME
INTEGER::N
REAL::Q1(1000)
REAL::Q20
REAL::Q2(1000)
REAL::I1
REAL::I2
REAL::C0
REAL::C1
REAL::C2
REAL::X
REAL::K
REAL::DETAT
INTEGER::I
C0 = (0.5*DETAT - K*X)/(0.5*DETAT + K - K*X)
C1 = (0.5*DETAT + K*X)/(0.5*DETAT + K - K*X)
C2 = (-0.5*DETAT +K - K*X)/(0.5*DETAT + K - K*X)
Q2(1) =Q20
DO I = 2,N
I2 = Q1(I)
I1 = Q1(I-1)
Q2(I) = C0*I2 + C1*I1 + C2*Q2(I-1)
END DO
END SUBROUTINE Mc_method

111
Fortran/XAJ.f90 Normal file
View File

@ -0,0 +1,111 @@
SUBROUTINE XAJ(FILELEN ,&
NODE ,& ! //
M ,& ! //
PAR ,& ! //
NAREA ,& ! //
AREA ,& ! //
UH ,& ! 线 //
DT ,& ! //
P ,& ! //
EP ,& ! //
W ,& ! 1. 2. 3. //
FR ,& ! //
S ,& ! //
QRSS0 ,& ! //
QRG0 ,& ! //
Q20 ,& ! //
X ,& ! //
K ,& ! //
DETAT ,& ! //
C0 ,& ! //
C1 ,& ! //
C2 ,& ! //
QOUT ) ! //
IMPLICIT NONE
INTEGER::NODE
REAL::X
REAL::K
REAL::DETAT
REAL::C0
REAL::C1
REAL::C2
INTEGER:: FILELEN
INTEGER::M !
REAL::PAR(13) ! 1.wum 2.wl 3.wdm
! 4.KC.c 6.b
! 7.imp1 8.sm 9.ex
!10.kg 11.kss 12.kkg
!13.kkss
integer::NAREA ! //
REAL::AREA(NAREA) !
REAL::Q1(NAREA,NODE)
REAL::UH(M) ! 线
REAL::DT !
REAL::P(NAREA,NODE) !
REAL::EP(NAREA,NODE) !
REAL::QR(NAREA,NODE) !
REAL::W(3) ! 1. 2. 3.
REAL::FR !
REAL::S !
REAL::QRSS0 !
REAL::QRG0 !
REAL::Q2(NAREA,NODE)
INTEGER::I,J
REAL::QOUT(NODE)
REAL::Q20(NAREA)
DO I = 1,NODE
QOUT(I) = 0.0
END DO
DO I =1,NAREA
CALL XAJMX( FILELEN ,&
NODE ,& ! //
M ,& ! //
PAR ,& ! //
AREA(I) ,& ! //
UH ,& ! 线 //
DT ,& ! //
P(I,:) ,& ! //
EP(I,:) ,& ! //
W ,& ! 1. 2. 3. //
FR ,& ! //
S ,& ! //
QRSS0 ,& ! //
QRG0 ,& ! //
QR(I,:) ) ! //
DO J = 1,NAREA
Q1(J,:)=QR(J,:)
END DO
CALL Mc_method( FILELEN ,& ! //
NODE ,& ! //
Q1(I,:) ,& ! //
Q20(I) ,& ! //
X ,& ! //
K ,& ! //
DETAT ,& ! //
C0 ,& ! //
C1 ,& ! //
C2 ,& ! //
Q2(I,:) ) ! //
END DO
DO I = 1,NAREA
DO J = 1,NODE
QOUT(J)= Q2(I,J) + QOUT(J)
END DO
END DO
END SUBROUTINE XAJ

412
Fortran/XAJMX.f90 Normal file
View File

@ -0,0 +1,412 @@
SUBROUTINE XAJMX( FILELEN ,&
N ,& ! //
M ,& ! //
PAR ,& ! //
AREA ,& ! //
UH ,& ! 线 //
DT ,& ! //
P ,& ! //
EP ,& ! //
W ,& ! 1. 2. 3. //
FR ,& ! //
S ,& ! //
QRSS0 ,& ! //
QRG0 ,& ! //
QR ) ! //
IMPLICIT NONE
!/////////////////////////////////////////////////////////////////////////////////////
INTEGER::N !
INTEGER::M !
REAL::PAR(13) ! 1.wum 2.wl 3.wdm
! 4.KC.c 6.b
! 7.imp1 8.sm 9.ex
!10.kg 11.kss 12.kkg
!13.kkss
REAL::AREA !
REAL::UH(M) ! 线
REAL::DT !
REAL::P(N) !
REAL::EP(N) !
REAL::QR(N) !
REAL::W(3) ! 1. 2. 3.
REAL::FR !
REAL::S !
REAL::QRSS0 !
REAL::QRG0 !
INTEGER::D
REAL::KSSD
REAL::KGD
REAL::E(3)
REAL::WM(3)
REAL::KC !
REAL::C !
REAL::B !
REAL::IMP1 !
REAL::SM !
REAL::EX !
REAL::KG !
REAL::KSS !
REAL::KKG !
REAL::KKSS !
!vb程序中未声明的变量
INTEGER::I ! //
INTEGER::J ! //
INTEGER::ICHECK !
INTEGER::NN
REAL(KIND=8),PARAMETER::C5=5.000000000
REAL::U
REAL::CI
REAL::CG
REAL::WM0
REAL::W0
REAL::PE
REAL::R
REAL::RIMP
REAL::WMM
REAL::A
REAL::X
REAL::RS
REAL::RSS
REAL::RGD
REAL::RG
REAL::SS
REAL::Q
REAL::KSSDD
REAL::KGDD
REAL::SMM
REAL::SMMF
REAL::SMF
REAL::AU
REAL::RSD
REAL::RSSD
REAL::QRS
REAL::QRSS
REAL::QRG
REAL::QTR
INTEGER:: FILELEN
REAL::WTEMP(3)
REAL::FRTEMP
REAL::STEMP
REAL::QRSS0TEMP
REAL::QRG0TEMP
!/////////////////////////////////////////////////////////////////////////////////////
DO I = 1,3
WTEMP(I) = W(I)
END DO
FRTEMP = FR
STEMP =S
QRSS0TEMP=QRSS0
QRG0TEMP=QRG0
!/////////////////////////////////////////////////////////////////////////////////////
D = 0
KSSD = 0.0
KGD = 0.0
do i = 1,3
E(I)=0.0
WM(I) =0.0
END DO
KC = 0.0
C = 0.0
B = 0.0
IMP1 = 0.0
SM = 0.0
EX = 0.0
KG = 0.0
KSS = 0.0
KKG = 0.0
KKSS = 0.0
U = 0.0
CI = 0.0
CG = 0.0
WM0 = 0.0
W0 = 0.0
PE = 0.0
R = 0.0
RIMP = 0.0
WMM = 0.0
A = 0.0
X = 0.0
RS = 0.0
RSS = 0.0
RGD = 0.0
RG = 0.0
SS = 0.0
Q = 0.0
KSSDD = 0.0
KGDD = 0.0
SMM = 0.0
SMMF = 0.0
SMF = 0.0
AU = 0.0
RSD = 0.0
RSSD = 0.0
QRS = 0.0
QRSS = 0.0
QRG = 0.0
QTR = 0.0
!
ICHECK = 1
DO I = 1, 3
WM(I) = PAR(I)
END DO
KC = PAR(4)
C = PAR(5)
B = PAR(6)
IMP1 = PAR(7)
SM = PAR(8)
EX = PAR(9)
KG = PAR(10)
KSS = PAR(11)
KKG = PAR(12)
KKSS = PAR(13)
DO I = 1, N
QR(I) = 0.0
END DO
U = AREA / 3.6 / DT
IF( DT.LE.24.0 )THEN
D = 24 / DT
CI = KKSS ** (1.0 / D)
CG = KKG ** (1.0 / D)
KSSD = (1.0 - (1.0 - (KG + KSS)) ** (1.0 / D)) / (1.0 + &
KG / KSS)
KGD = KSSD * KG / KSS
ELSE
ICHECK = 0
END IF
DO I = 1 , N
IF (EP(I) .LT. 0.0)THEN
EP(I) = 0.0
END IF
IF (P(I) .LT. 0.0)THEN
P(I) = 0.0
END IF
EP(I) = EP(I) * KC
WM0 = WM(1) + WM(2) + WM(3)
W0 = W(1) + W(2) + W(3)
PE = P(I) - EP(I)
!
R = 0.0
RIMP = 0.0
IF(PE.GT.0.0)THEN
WMM = (1.0 + B) * WM0 / (1.0 - IMP1)
IF ((WM0 - W0).LE.0.0001)THEN
A = WMM
ELSE
A = WMM * (1.0 - (1.0 - W0 / WM0) ** (1.0 / (1.0 + B)))
END IF
IF ((PE + A) .LT. WMM) THEN
R = PE - WM0 + W0 + WM0 * ((1.0 - (PE + A) / WMM) &
** (1.0 + B))
ELSE
R = PE - (WM0 - W0)
END IF
RIMP = PE * IMP1
END IF
IF ((W(1) + P(I)) .GT. EP(I)) THEN
E(1) = EP(I)
E(2) = 0.0
E(3) = 0.0
ELSE
E(1) = W(1) + P(I)
E(2) = (EP(I) - E(1)) * W(2) / WM(2)
IF (W(2) .LE.( C * WM(2))) THEN
E(2) = C * (EP(I) - E(1))
E(3) = 0.0
IF (W(2) .GE. (C * (EP(I) - E(1)))) THEN
E(2) = C * (EP(I) - E(1))
E(3) = 0.0
ELSE
E(2) = W(2)
E(3) = C * (EP(I) - E(1) - E(2))
END IF
END IF
END IF
W(1) = W(1) + P(I) - R - E(1)
W(2) = W(2) - E(2)
W(3) = W(3) - E(3)
IF (W(1) .GT. WM(1)) THEN
W(2) = W(1) - WM(1) + W(2)
W(1) = WM(1)
IF (W(2) .GT. WM(2)) THEN
W(3) = W(3) + W(2) - WM(2)
W(2) = WM(2)
END IF
END IF
X = FR
IF (PE .LE.0.0) THEN
RS = 0.0
RSS = S * KSSD * FR
RGD = S * FR * KGD
S = S - (RSS + RG) / FR
ELSE
FR = R / PE
S = X * S / FR
SS = S
Q = R / FR
NN = INT(Q / C5) + 1 ! vb程序中C5是双精度常数5
Q = Q / NN
KSSDD = (1.0 - (1.0 - (KGD + KSSD)) ** (1.0 / NN)) /&
(1.0 + KGD / KSSD)
KGDD = KSSDD * KGD / KSSD
RS = 0.0
RSS = 0.0
RG = 0.0
SMM = (1 + EX) * SM
IF (EX .LT. 0.001) THEN
SMMF = SMM
ELSE
SMMF = SMM * (1.0 - (1.0 - FR) ** (1.0 / EX))
END IF
SMF = SMMF / (1.0 + EX)
DO J = 1 , NN
IF (S .GT. SMF) THEN
S = SMF
END IF
AU = SMMF * (1.0 - (1.0 - S / SMF) ** (1.0 /&
(1.0 + EX)))
IF ((Q + AU) .LE. 0.0) THEN
RSD = 0.0
RSSD = 0.0
RGD = 0.0
S = 0.0
ELSE IF ((Q + AU) .GE. SMMF) THEN
RSD = (Q + S - SMF) * FR
RSSD = SMF * KSSDD * FR
RGD = SMF * FR * KGDD
S = SMF - (KSSD + KGD) / FR
ELSE IF ((Q + AU) .LT. SMMF) THEN
RSD = (Q - SMF + S + SMF * (1.0 - (Q + AU)&
/ SMMF) ** (1.0 + EX)) * FR
RSSD = (S + Q - RSD / FR) * KSSDD * FR
RGD = (S + Q - RSD / FR) * KGDD * FR
S = S + Q - (RSD + RSSD + RGD) / FR
END IF
RS = RS + RSD
RSS = RSS + RSSD
RG = RG + RGD
END DO
END IF
RS = RS * (1.0 - IMP1)
RSS = RSS * (1.0 - IMP1)
RG = RG * (1.0 - IMP1)
QRS = (RS + RIMP) * U
QRSS = QRSS0 * CI + RSS * (1.0 - CI) * U
QRG = QRG0 * CG + RG * (1.0 - CG) * U
QTR = QRS + QRSS + QRG
DO J = 1 , M
IF ((I + J - 1) .LE. N) THEN
QR(I + J - 1) = QR(I + J - 1) + QTR * UH(J)
END IF
END DO
QRSS0 = QRSS
QRG0 = QRG
END DO
DO I = 1,3
W(I) = WTEMP(I)
END DO
FR = FRTEMP
S =STEMP
QRSS0=QRSS0TEMP
QRG0=QRG0TEMP
END SUBROUTINE XAJMX

27
FortranWebApi.csproj Normal file
View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Serilog" Version="4.2.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="lib{{FortranFunctionName}}.so">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,32 @@
@FortranWebApi_HostAddress = http://localhost:5000
### 测试Fortran请求
POST {{FortranWebApi_HostAddress}}/FortranCalculate
Content-Type: application/json
{
"text": "{\"FuncName\":\"calculate_main\",\"ClassName\":\"\",\"Par\":[ {"Name":"FILELEN","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"NODE","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"M","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"PAR","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"NAREA","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"AREA","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"UH","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"DT","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"P","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"EP","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"W","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"FR","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"S","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"QRSS0","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"QRG0","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"Q20","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"X","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"K","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"DETAT","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"C0","DataType":"1","ArrayType":"0","IsOut":"1","Data":0},
{"Name":"C1","DataType":"1","ArrayType":"0","IsOut":"1","Data":0},
{"Name":"C2","DataType":"1","ArrayType":"0","IsOut":"1","Data":0},
{"Name":"QOUT","DataType":"1","ArrayType":"1","IsOut":"1","Data":[]}]}"
}

31
Models/ApiResponse.cs Normal file
View File

@ -0,0 +1,31 @@
using System.Text.Json.Serialization;
namespace FortranWebApi.Models
{
public class ApiResponse<T>
{
[JsonPropertyName("message")]
public string Message { get; set; } = "Success";
[JsonPropertyName("success")]
public bool Success { get; set; } = true;
[JsonPropertyName("data")]
public ApiResponseData<T>? Data { get; set; }
}
public class ApiResponseData<T>
{
[JsonPropertyName("contentType")]
public string? ContentType { get; set; }
[JsonPropertyName("serializerSettings")]
public object? SerializerSettings { get; set; }
[JsonPropertyName("statusCode")]
public int? StatusCode { get; set; }
[JsonPropertyName("value")]
public T? Value { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using System.Text.Json.Serialization;
namespace FortranWebApi.Models
{
public class FortranParameter
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("dataType")]
public string DataType { get; set; } = "0";
[JsonPropertyName("arrayType")]
public string ArrayType { get; set; } = "0";
[JsonPropertyName("isOut")]
public string IsOut { get; set; } = "2";
[JsonPropertyName("data")]
public object? Data { get; set; }
}
}

13
Models/FortranRequest.cs Normal file
View File

@ -0,0 +1,13 @@
using System.Text.Json.Serialization;
namespace FortranWebApi.Models
{
public class FortranRequest
{
public string FuncName { get; set; } = string.Empty;
public string ClassName { get; set; } = string.Empty;
[JsonPropertyName("par")]
public List<FortranParameter> Parameters { get; set; } = new List<FortranParameter>();
}
}

View File

@ -0,0 +1,7 @@
namespace FortranWebApi.Models
{
public class FortranRequestWrapper
{
public string Text { get; set; } = string.Empty;
}
}

80
Program.cs Normal file
View File

@ -0,0 +1,80 @@
using Serilog;
using FortranWebApi.Services;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
// 设置库搜索路径
string currentDir = Directory.GetCurrentDirectory();
Environment.SetEnvironmentVariable("LD_LIBRARY_PATH",
$"{Environment.GetEnvironmentVariable("LD_LIBRARY_PATH")}:{currentDir}");
var builder = WebApplication.CreateBuilder(args);
// 添加健康检查服务
builder.Services.AddHealthChecks();
// 配置Serilog
Log.Logger = new LoggerConfiguration()
.WriteTo.Console(outputTemplate:
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File("logs/log-.txt",
rollingInterval: RollingInterval.Day,
outputTemplate:
"{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
.CreateLogger();
builder.Host.UseSerilog(); // 将Serilog添加到Host
// 配置JSON序列化选项使用驼峰命名法
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<FortranInteropService>();
// 配置CORS
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCors();
app.UseAuthorization();
// 映射健康检查端点
app.MapHealthChecks("/health");
app.MapControllers();
try
{
Log.Information("启动应用程序...");
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "应用程序启动失败");
}
finally
{
Log.CloseAndFlush();
}

View File

@ -0,0 +1,14 @@
{
"profiles": {
"FortranWebApi": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "http://0.0.0.0:5000"
}
}
}

View File

@ -0,0 +1,563 @@
using System.Runtime.InteropServices;
using FortranWebApi.Models;
using System.Text.Json;
using System.Runtime.InteropServices.Marshalling;
using System.IO;
namespace FortranWebApi.Services
{
public class FortranInteropService
{
// 静态构造函数设置DLL导入解析器
static FortranInteropService()
{
// 添加当前目录到库搜索路径
NativeLibrary.SetDllImportResolver(typeof(FortranInteropService).Assembly, (name, assembly, path) =>
{
if (name == "libMSJGMX.so")
{
// 尝试从当前目录加载
string currentDir = Directory.GetCurrentDirectory();
string libraryPath = Path.Combine(currentDir, "libMSJGMX.so");
if (File.Exists(libraryPath))
{
return NativeLibrary.Load(libraryPath);
}
}
// 回退到默认加载行为
return IntPtr.Zero;
});
}
// DllImport声明
[DllImport("libMSJGMX.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "MSJGMX")]
private static extern void MSJGMX(
ref int FILELEN,
ref int NODE,
ref int M,
float[] PAR,
ref int NAREA,
float[] AREA,
float[] UH,
ref float DT,
float[] P,
[MarshalAs(UnmanagedType.LPArray, SizeConst = 0)] float[,] EP,
float[] W,
ref float FR,
ref float S,
ref float QRSS0,
ref float QRG0,
float[] Q20,
ref float X,
ref float K,
ref float DETAT,
out float C0,
out float C1,
out float C2,
float[] QOUT
);
public string ProcessFortranRequest(string requestText)
{
try
{
// 解析请求
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
var request = JsonSerializer.Deserialize<FortranRequest>(requestText, options);
if (request == null)
{
throw new ArgumentException("无效的请求格式");
}
// 准备输入参数
var parameters = request.Parameters;
// 提取参数
int FILELEN = GetIntParameter(parameters, "FILELEN");
int NODE = GetIntParameter(parameters, "NODE");
int M = GetIntParameter(parameters, "M");
float[] PAR = GetFloatArrayParameter(parameters, "PAR");
int NAREA = GetIntParameter(parameters, "NAREA");
float[] AREA = GetFloatArrayParameter(parameters, "AREA");
float[] UH = GetFloatArrayParameter(parameters, "UH");
float DT = GetFloatParameter(parameters, "DT");
float[] P = GetFloatArrayParameter(parameters, "P");
float[,] EP = GetFloatParameter(parameters, "EP");
float[] W = GetFloatArrayParameter(parameters, "W");
float FR = GetFloatParameter(parameters, "FR");
float S = GetFloatParameter(parameters, "S");
float QRSS0 = GetFloatParameter(parameters, "QRSS0");
float QRG0 = GetFloatParameter(parameters, "QRG0");
float[] Q20 = GetFloatArrayParameter(parameters, "Q20");
float X = GetFloatParameter(parameters, "X");
float K = GetFloatParameter(parameters, "K");
float DETAT = GetFloatParameter(parameters, "DETAT");
float C0;
float C1;
float C2;
// 准备数组参数
float[] QOUT = new float[10000]; // 输出数组初始大小为10000
// 调用Fortran函数
MSJGMX(
ref FILELEN,
ref NODE,
ref M,
PAR,
ref NAREA,
AREA,
UH,
ref DT,
P,
ref EP,
W,
ref FR,
ref S,
ref QRSS0,
ref QRG0,
Q20,
ref X,
ref K,
ref DETAT,
out C0,
out C1,
out C2,
QOUT
);
// 更新输出参数
UpdateParameter(parameters, "C0", C0);
UpdateParameter(parameters, "C1", C1);
UpdateParameter(parameters, "C2", C2);
UpdateArrayParameter(parameters, "QOUT", QOUT);
// 处理输出数组
// 处理输出数组 QOUT
// 注意:没有找到明确的长度参数,使用非零元素数量
{
int nonZeroCount = 0;
for (int i = 0; i < QOUT.Length; i++)
{
if (QOUT[i] != 0) nonZeroCount = i + 1;
}
if (nonZeroCount > 0)
{
float[] resultArray = new float[nonZeroCount];
Array.Copy(QOUT, resultArray, nonZeroCount);
UpdateArrayParameter(parameters, "QOUT", resultArray);
}
}
// 返回结果 - 只返回原始请求的结构,但包含更新后的参数
var result = new FortranRequest
{
FuncName = request.FuncName,
ClassName = request.ClassName,
Parameters = parameters
};
return JsonSerializer.Serialize(result, options);
}
catch (Exception ex)
{
return JsonSerializer.Serialize(new { error = ex.Message });
}
}
private float GetFloatParameter(List<FortranParameter> parameters, string name)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return 0.0f;
}
if (param.Data is JsonElement element)
{
if (element.ValueKind == JsonValueKind.Number)
{
return element.GetSingle();
}
}
return Convert.ToSingle(param.Data);
}
private double GetDoubleParameter(List<FortranParameter> parameters, string name)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return 0.0;
}
if (param.Data is JsonElement element)
{
if (element.ValueKind == JsonValueKind.Number)
{
return element.GetSingle();
}
}
return Convert.ToDouble(param.Data);
}
private int GetIntParameter(List<FortranParameter> parameters, string name)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return 0;
}
if (param.Data is JsonElement element)
{
if (element.ValueKind == JsonValueKind.Number)
{
return element.GetInt32();
}
}
return Convert.ToInt32(param.Data);
}
private int[] GetIntArrayParameter(List<FortranParameter> parameters, string name)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return Array.Empty<int>();
}
if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
{
var array = new List<int>();
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.Number)
{
array.Add(item.GetInt32());
}
}
return array.ToArray();
}
if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
{
var array = new List<int>();
foreach (var item in enumerable)
{
array.Add(Convert.ToInt32(item));
}
return array.ToArray();
}
return Array.Empty<int>();
}
private float[] GetFloatArrayParameter(List<FortranParameter> parameters, string name)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return Array.Empty<float>();
}
if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
{
var array = new List<float>();
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.Number)
{
array.Add(item.GetSingle());
}
}
return array.ToArray();
}
if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
{
var array = new List<float>();
foreach (var item in enumerable)
{
array.Add(Convert.ToSingle(item));
}
return array.ToArray();
}
return Array.Empty<float>();
}
private double[] GetDoubleArrayParameter(List<FortranParameter> parameters, string name)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return Array.Empty<double>();
}
if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
{
var array = new List<double>();
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.Number)
{
array.Add(item.GetSingle());
}
}
return array.ToArray();
}
if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
{
var array = new List<double>();
foreach (var item in enumerable)
{
array.Add(Convert.ToSingle(item));
}
return array.ToArray();
}
return Array.Empty<double>();
}
private void UpdateParameter(List<FortranParameter> parameters, string name, object value)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param != null)
{
param.Data = value;
}
}
private void UpdateArrayParameter(List<FortranParameter> parameters, string name, float[] value)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param != null)
{
param.Data = value;
}
}
private void UpdateDoubleArrayParameter(List<FortranParameter> parameters, string name, double[] value)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param != null)
{
param.Data = value;
}
}
private void UpdateIntArrayParameter(List<FortranParameter> parameters, string name, int[] value)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param != null)
{
param.Data = value;
}
}
// 添加新的辅助方法来处理二维数组
private double[,] GetDouble2DArrayParameter(List<FortranParameter> parameters, string name, int rows, int cols)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return new double[rows, cols];
}
double[,] result = new double[rows, cols];
if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
{
int index = 0;
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.Number)
{
int row = index / cols;
int col = index % cols;
if (row < rows && col < cols)
{
result[row, col] = item.GetDouble();
}
index++;
}
}
}
else if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
{
int index = 0;
foreach (var item in enumerable)
{
int row = index / cols;
int col = index % cols;
if (row < rows && col < cols)
{
result[row, col] = Convert.ToDouble(item);
}
index++;
}
}
return result;
}
// 添加更新二维数组参数的方法
private void UpdateDouble2DArrayParameter(List<FortranParameter> parameters, string name, double[,] value)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param != null)
{
// 将二维数组转换为一维数组以便于JSON序列化
int rows = value.GetLength(0);
int cols = value.GetLength(1);
double[] flatArray = new double[rows * cols];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
flatArray[i * cols + j] = value[i, j];
}
}
param.Data = flatArray;
}
}
// float版本
private float[,] GetFloat2DArrayParameter(List<FortranParameter> parameters, string name, int rows, int cols)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return new float[rows, cols];
}
float[,] result = new float[rows, cols];
if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
{
int index = 0;
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.Number)
{
int row = index / cols;
int col = index % cols;
if (row < rows && col < cols)
{
result[row, col] = item.GetSingle();
}
index++;
}
}
}
else if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
{
int index = 0;
foreach (var item in enumerable)
{
int row = index / cols;
int col = index % cols;
if (row < rows && col < cols)
{
result[row, col] = Convert.ToSingle(item);
}
index++;
}
}
return result;
}
private void UpdateFloat2DArrayParameter(List<FortranParameter> parameters, string name, float[,] value)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param != null)
{
int rows = value.GetLength(0);
int cols = value.GetLength(1);
float[] flatArray = new float[rows * cols];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
flatArray[i * cols + j] = value[i, j];
}
}
param.Data = flatArray;
}
}
// int版本
private int[,] GetInt2DArrayParameter(List<FortranParameter> parameters, string name, int rows, int cols)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param == null || param.Data == null)
{
return new int[rows, cols];
}
int[,] result = new int[rows, cols];
if (param.Data is JsonElement element && element.ValueKind == JsonValueKind.Array)
{
int index = 0;
foreach (var item in element.EnumerateArray())
{
if (item.ValueKind == JsonValueKind.Number)
{
int row = index / cols;
int col = index % cols;
if (row < rows && col < cols)
{
result[row, col] = item.GetInt32();
}
index++;
}
}
}
else if (param.Data is System.Collections.IEnumerable enumerable && !(param.Data is string))
{
int index = 0;
foreach (var item in enumerable)
{
int row = index / cols;
int col = index % cols;
if (row < rows && col < cols)
{
result[row, col] = Convert.ToInt32(item);
}
index++;
}
}
return result;
}
private void UpdateInt2DArrayParameter(List<FortranParameter> parameters, string name, int[,] value)
{
var param = parameters.FirstOrDefault(p => p.Name == name);
if (param != null)
{
int rows = value.GetLength(0);
int cols = value.GetLength(1);
int[] flatArray = new int[rows * cols];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
flatArray[i * cols + j] = value[i, j];
}
}
param.Data = flatArray;
}
}
}
}

16
appsettings.json Normal file
View File

@ -0,0 +1,16 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://0.0.0.0:5000"
}
}
}
}