This commit is contained in:
tp 2025-05-14 17:42:10 +08:00
commit a024039f05
20 changed files with 2329 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 libMAIN_UFRN.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/libMAIN_UFRN.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/libMAIN_UFRN.so
# 设置 LD_LIBRARY_PATH
ENV LD_LIBRARY_PATH=/app
# 设置端口和监听地址
ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000
ENTRYPOINT ["dotnet", "FortranWebApi.dll"]

329
Fortran/1.json Normal file
View File

@ -0,0 +1,329 @@
{
"fortranSourceFile": "D:\\\u5DE5\u4F5C2025\\\u7B97\u6CD5\u5E73\u53F0\\dll\\\u591A\u6CB3\u9053\u4E00\u7EF4\u6C34\u52A8\u529B\u6A21\u578B\\MAIN_UFRN\\MAIN_UFRN\\MAIN_UFRN - \u526F\u672C.f90",
"fortranFunctionName": "MAIN_UFRN",
"projectName": "FortranWebApi",
"outputDirectory": "D:\\\u5DE5\u4F5C2025\\\u7B97\u6CD5\u5E73\u53F0\\\u8F93\u51FA\u5E93\\\u591A\u6CB3\u9053\u4E00\u7EF4\u6C34\u52A8\u529B\u6A21\u578B",
"cmbLanguage": "Fortran",
"parameters": [
{
"name": "nriver",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "nsect",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "krc",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "ndata",
"dataType": "Integer",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Ns",
"dataType": "Integer",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Pc",
"dataType": "Integer",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Nrc",
"dataType": "Integer",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Lc",
"dataType": "Integer",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Dric",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "XJ",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Asave",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "ds",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "bd",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "zd",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "sm",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "rough",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "ZZ0",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Zctr",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Qp",
"dataType": "Float",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "UB1",
"dataType": "Integer",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "UB2",
"dataType": "Integer",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "DB1",
"dataType": "Integer",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "DB2",
"dataType": "Integer",
"arrayType": "OneDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "UBV",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "NUB",
"dataType": "Integer",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "DBV",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Gate",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "NDB",
"dataType": "Integer",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Aphi",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "period",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "dt",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "sita",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "sorz",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "sorq",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "epsz",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "epsq",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Bsor1",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Bsor2",
"dataType": "Float",
"arrayType": "Scalar",
"direction": "Input",
"description": "",
"isSelected": true
},
{
"name": "Z",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Output",
"description": "",
"isSelected": true
},
{
"name": "Q",
"dataType": "Float",
"arrayType": "TwoDimensional",
"direction": "Output",
"description": "",
"isSelected": true
}
]
}

BIN
Fortran/1.xlsx Normal file

Binary file not shown.

350
Fortran/MAIN_UFRN.f90 Normal file
View File

@ -0,0 +1,350 @@
SUBROUTINE MAIN_UFRN(nriver ,& !
nsect ,& !
krc ,& !
ndata ,& !
Ns ,& !
Pc ,& !
Nrc ,& !
Lc ,& !
Dric ,& !
XJ ,& !
Asave ,& !
ds ,& !
bd ,& !
zd ,& !
sm ,& !
rough ,& !
ZZ0 ,& !
Zctr ,& !
Qp ,& !
UB1 ,& !112,3
UB2 ,& !212
DB1 ,& !112,3
DB2 ,& !212
UBV ,& !
NUB ,& !
DBV ,& !
Gate ,& !Gate(1,i) = Gate(2,i) = Gate(3,i) = C1Gate(4,i) = C2 Q=C1*B*e*dZ^C2中的C1和C2
NDB ,& !
Aphi ,& !
period ,& !
dt ,& !
sita ,& !
sorz ,& !
sorq ,& !
epsz ,& !
epsq ,& !
Bsor1 ,& !
Bsor2 ,& !
Z ,& !
Q )& !
BIND(C, NAME="MAIN_UFRN")
!DEC$ ATTRIBUTES DLLEXPORT::MAIN_UFRN
IMPLICIT NONE
INTEGER::nriver !
INTEGER::nsect !
INTEGER::krc !
INTEGER::ndata !
INTEGER::MRIVER
integer River,tstep
INTEGER::I
INTEGER::II
!
INTEGER::Ns(nriver) ! : NRIVER
INTEGER::Pc(nriver) ! : NRIVER
INTEGER::Nrc(krc,nriver) ! 1-2-3-: KRC, NRIVER
INTEGER::Lc(krc,nriver) ! : KRC, NRIVER
!
INTEGER::UB1(nriver) ! 1-2-3-: NRIVER
INTEGER::UB2(nriver) ! 1-2-: NRIVER
INTEGER::DB1(nriver) ! : NRIVER
INTEGER::DB2(nriver) ! : NRIVER
INTEGER::NUB(2,nriver) ! : 2, NRIVER
INTEGER::NDB(2,nriver) ! : 2, NRIVER
REAL::ZZ0 ! m
REAL::Zctr ! m
REAL::period !
REAL::dt !
REAL::sita ! 0.5~1.0
REAL::sorz ! 0~1
REAL::sorq ! 0~1
REAL::epsz ! m
REAL::epsq ! m?/s
REAL::Bsor1 !
REAL::Bsor2 !
REAL::ql
REAL::condu,condd(3)
REAL::Bs,As,Rs,Cs
!
REAL::Dric(krc,nriver) ! 1-1: KRC, NRIVER
REAL::Qj(ndata,krc,nriver) ! : NDATA, KRC, NRIVER
REAL::Asave(krc,nriver) ! m?: KRC, NRIVER
!
REAL::ds(nsect - 1,nriver) ! m: nsect - 1, NRIVER
REAL::bd(nsect,nriver) ! m: NSECT, NRIVER
REAL::zd(nsect,nriver) ! m: NSECT, NRIVER
REAL::sm(nsect,nriver) ! -: NSECT, NRIVER
REAL::rough(nsect,nriver) ! : NSECT, NRIVER
!
REAL::UBV(ndata,nriver) ! /: NDATA, NRIVER
REAL::DBV(ndata,nriver) ! /: NDATA, NRIVER
REAL::Gate(4,nriver) ! C1C2: 4, NRIVER
REAL::Aphi(2,nriver) ! : 2, NRIVER
REAL::Qp(ndata) ! m?/s: NDATA
REAL::Z0(nsect,nriver)
REAL::Q0(nsect,nriver)
REAL::Z(nsect,nriver)
REAL::Q(nsect,nriver)
REAL::V(nsect,nriver)
REAL::Zc(nsect,nriver),Qc(nsect,nriver)
REAL::XJ(ndata,nriver*krc)
REAL::maxtstep
REAL::maxiter
REAL::ttime
REAL::fc
REAL::Scanal
REAL::dzmax
REAL::dqmax
REAL::dz
REAL::dq
REAL::maxz_r
REAL::maxz_s
REAL::maxq_r
REAL::maxq_s
INTEGER::Is
INTEGER::iter
INTEGER::J,K
MRIVER = nsect - 1
Scanal = 0.0 ! Scanalql
DO I = 1,ndata
DO J = 1,KRC
DO K = 1,NRIVER
Qj(i,j,k) = xj(i,j*k)
end do
end do
end do
DO J = 1,nriver
DO I = 1,Ns(j)-1
Scanal = Scanal + ds(i,j) ! 0
END DO
END DO
!
maxtstep=period*3600/dt
maxiter=1000 ! 仿
!
DO river=1,nriver
DO Is=1,Ns(river)
Z0(Is,river)=ZZ0
Q0(Is,river)=0.0
END DO
END DO
DO tstep=1,maxtstep !
ttime=dt*tstep/3600.0 !
iter=0
DO river=1,nriver
DO Is=1,Ns(river)
Z(Is,river)=Z0(Is,river)
Q(Is,river)=Q0(Is,river)
END DO
END DO
!
call int_a( ttime ,& ! //
ndata ,& !
Qp ,& ! 线
fc ) ! //
ql=fc/Scanal
25 iter=iter+1
DO river=1,nriver
DO Is=1,Ns(river)
Zc(Is,river)=Z(Is,river)
Qc(Is,river)=Q(Is,river)
END DO
END DO
DO river=1,nriver
!
call sub_bound( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river ,&
tstep ,&
Ns ,&
Pc ,&
Nrc ,&
Lc ,&
Dric ,&
Qj ,&
Asave ,&
UB1 ,&
UB2 ,&
DB1 ,&
DB2 ,&
NUB ,&
NDB ,&
UBV ,&
Aphi ,&
DBV ,&
Gate ,&
ql ,&
Zctr ,&
dt ,&
sita ,&
Bsor1 ,&
Bsor2 ,&
Z0 ,&
Q0 ,&
Z ,&
Q ,&
V ,&
condu ,&
condd )
! Z和流量Q
call sub_QZ( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river ,&
tstep ,&
Ns ,&
Pc ,&
Nrc ,&
Lc ,&
Dric ,&
Qj ,&
Asave ,&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
UB1 ,&
UB2 ,&
DB1 ,&
DB2 ,&
NUB ,&
NDB ,&
UBV ,&
Aphi ,&
DBV ,&
Gate ,&
ql ,&
Zctr ,&
dt ,&
sita ,&
Bsor1 ,&
Bsor2 ,&
Z0 ,&
Q0 ,&
Z ,&
Q ,&
V ,&
condu ,&
condd ,&
Bs ,&
As ,&
Rs ,&
Cs )
END DO
dzmax=0.0
dqmax=0.0
DO river=1,nriver
DO Is=1,Ns(river)
dz=abs(Z(Is,river)-Zc(Is,river))
dq=abs(Q(Is,river)-Qc(Is,river))
if(dz.gt.dzmax)then
dzmax=dz
maxz_r=river
maxz_s=Is
end if
if(dq.gt.dqmax)then
dqmax=dq
maxq_r=river
maxq_s=Is
end if
END DO
END DO
if(dzmax.gt.epsz.or.dqmax.gt.epsq)then
DO river=1,nriver
DO Is=1,Ns(river)
Z(Is,river)=(1.0-sorz)*Zc(Is,river)&
+sorz*Z(Is,river)
Q(Is,river)=(1.0-sorq)*Qc(Is,river)&
+sorq*Q(Is,river)
END DO
END DO
if(iter.le.maxiter)then
goto 25
else
exit
end if
else
DO river=1,nriver
DO Is=1,Ns(river)
!
call sub_sect(NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river,Is,Z(Is,river),&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
V(Is,river)=Q(Is,river)/As
END DO
END DO
DO river=1,nriver
DO Is=1,Ns(river)
Z0(Is,river)=Z(Is,river)
Q0(Is,river)=Q(Is,river)
END DO
END DO
end if
end do
END SUBROUTINE MAIN_UFRN

164
Fortran/SUB_BOUND.f90 Normal file
View File

@ -0,0 +1,164 @@
! ==================================================================================
!
! ==================================================================================
!
! ndata个数据点1
!
! Q=C1*B*e*dZ^C2Z>Ztide且Z>Zctr时开闸
! Zctr是挡潮闸运行控制水位
! ----------------------------------------------------------------------------------
SUBROUTINE SUB_BOUND( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river ,&
tstep ,&
Ns ,&
Pc ,&
Nrc ,&
Lc ,&
Dric ,&
Qj ,&
Asave ,&
UB1 ,&
UB2 ,&
DB1 ,&
DB2 ,&
NUB ,&
NDB ,&
UBV ,&
Aphi ,&
DBV ,&
Gate ,&
ql ,&
Zctr ,&
dt ,&
sita ,&
Bsor1 ,&
Bsor2 ,&
Z0 ,&
Q0 ,&
Z ,&
Q ,&
V ,&
condu ,&
condd )
INTEGER::NRIVER
INTEGER::NSECT
INTEGER::MRIVER
INTEGER::KRC
INTEGER::NDATA
INTEGER RIVER,TSTEP
! node
INTEGER::Ns(nriver),Pc(nriver),Nrc(krc,nriver),Lc(krc,nriver)
REAL::Dric(krc,nriver),Qj(ndata,krc,nriver),Asave(krc,nriver)
! boundary
INTEGER::UB1(nriver),UB2(nriver),DB1(nriver)
INTEGER::DB2(nriver),NUB(2,nriver),NDB(2,nriver)
REAL::UBV(ndata,nriver),Aphi(2,nriver),DBV(ndata,nriver)
REAL::Gate(4,nriver),ql,Zctr
! calcu
REAL::dt,sita,Bsor1,Bsor2
! zzqq
REAL::Z0(nsect,nriver),Q0(nsect,nriver),Z(nsect,nriver)
REAL::Q(nsect,nriver),V(nsect,nriver)
! r_bv
REAL::condu,condd(3)
REAL:: ZQ(NDATA)
TC=DT*FLOAT(TSTEP)/3600.0
!
IF(UB2(RIVER).EQ.1)THEN !
DO II=1,NDATA
ZQ(II)=UBV(II,RIVER)
END DO
CALL INT_A(TC,NDATA,ZQ,FC)
CONDU=FC
ELSEIF(UB2(RIVER).EQ.2)THEN !
IR=NUB(1,RIVER)
IS=NUB(2,RIVER)
IF(UB1(RIVER).EQ.1)THEN
CONDU=Z(IS,IR)
END IF
IF(UB1(RIVER).EQ.2)THEN
CONDU=Q(IS+1,IR)
END IF
END IF
!
IF(DB2(RIVER).EQ.1)THEN
DO II=1,NDATA
ZQ(II)=DBV(II,RIVER)
END DO
CALL INT_A(TC,NDATA,ZQ,FC)
IF(DB1(RIVER).EQ.1)THEN
CONDD(1)=1.0
CONDD(2)=0.0
CONDD(3)=FC
ELSE IF(DB1(RIVER).EQ.2)THEN
CONDD(1)=0.0
CONDD(2)=1.0
CONDD(3)=FC
ELSE IF(DB1(RIVER).EQ.3)THEN
ZU0=Z0(NS(RIVER)-1,RIVER)
ZU=Z0(NS(RIVER)-1,RIVER)
ZU=(1-BSOR1)*ZU0+BSOR1*ZU
B=GATE(1,RIVER)
QMAX=GATE(2,RIVER)
C1=GATE(3,RIVER)
C2=GATE(4,RIVER)
IF(ZU>FC.AND.ZU>=ZCTR)THEN
DZ=ZU-FC
EK=5.0*DZ
IF(DZ<0.15)THEN
E=0.0
END IF
QQ=C1*B*EK*DZ**C2
QQ=(1-BSOR1)*Q0(NS(RIVER),RIVER)+BSOR1*QQ
IF(QQ>QMAX)THEN
QQ=QMAX
END IF
CONDD(1)=0.0
CONDD(2)=1.0
CONDD(3)=QQ
ELSE
CONDD(1)=0.0
CONDD(2)=1.0
CONDD(3)=0.0
END IF
END IF
ELSEIF(DB2(RIVER).EQ.2)THEN
IR=NDB(1,RIVER)
IS=NDB(2,RIVER)
IF(DB1(RIVER).EQ.1)THEN
CONDD(1)=1.0
CONDD(2)=0.0
CONDD(3)=Z(IS,IR)
ELSE
AH=APHI(1,RIVER)
PHI=APHI(2,RIVER)
IF(Z(NS(RIVER),RIVER)>=Z(IS,IR))THEN
QQ=AH*PHI*SQRT(2*9.8*(Z(NS(RIVER),RIVER)-Z(IS,IR)))
ELSE
QQ=-AH*PHI*SQRT(2*9.8*(Z(IS,IR)-Z(NS(RIVER),RIVER)))
END IF
QQ=(1-BSOR2)*Q0(NS(RIVER),RIVER)+BSOR2*QQ
CONDD(1)=0.0
CONDD(2)=1.0
CONDD(3)=QQ
END IF
END IF
END SUBROUTINE SUB_BOUND

42
Fortran/SUB_INT_A.f90 Normal file
View File

@ -0,0 +1,42 @@
!
SUBROUTINE INT_A( TC ,& ! //
N ,& !
F ,& ! 线
FC ) ! //
IMPLICIT NONE
!
REAL::TC
INTEGER::N
REAL::F(N)
!
REAL::FC
!
INTEGER::I
REAL::T
REAL::T1
REAL::T2
!
DO I=1,N
T=1.0*FLOAT(I-1)
IF(TC.EQ.T)THEN
FC=F(I)
END IF
END DO
! 线
DO I=1,N-1
T1=1.0*FLOAT(I-1)
T2=1.0*FLOAT(I)
IF(TC.GT.T1.AND.TC.LT.T2)THEN
FC=F(I)+(TC-T1)*(F(I+1)-F(I))/(T2-T1)
EXIT
END IF
END DO
END SUBROUTINE INT_A

350
Fortran/SUB_QZ.f90 Normal file
View File

@ -0,0 +1,350 @@
! ==================================================================================
! Z和流量Q的子程序
! ==================================================================================
subroutine sub_QZ( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river ,&
tstep ,&
Ns ,&
Pc ,&
Nrc ,&
Lc ,&
Dric ,&
Qj ,&
Asave ,&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
UB1 ,&
UB2 ,&
DB1 ,&
DB2 ,&
NUB ,&
NDB ,&
UBV ,&
Aphi ,&
DBV ,&
Gate ,&
ql ,&
Zctr ,&
dt ,&
sita ,&
Bsor1 ,&
Bsor2 ,&
Z0 ,&
Q0 ,&
Z ,&
Q ,&
V ,&
condu ,&
condd ,&
Bs ,&
As ,&
Rs ,&
Cs )
INTEGER::NRIVER
INTEGER::NSECT
INTEGER::MRIVER
INTEGER::KRC
INTEGER::NDATA
integer River,tstep
REAL Qjj(ndata)
real L(nsect),M(nsect),P(nsect),R(nsect)
! node
INTEGER::Ns(nriver),Pc(nriver),Nrc(krc,nriver),Lc(krc,nriver)
REAL::Dric(krc,nriver),Qj(ndata,krc,nriver),Asave(krc,nriver)
! section
REAL::ds(mriver,nriver),bd(nsect,nriver),zd(nsect,nriver)
REAL::sm(nsect,nriver), rough(nsect,nriver)
! boundary
INTEGER::UB1(nriver),UB2(nriver),DB1(nriver),DB2(nriver)
INTEGER::NUB(2,nriver),NDB(2,nriver)
REAL::UBV(ndata,nriver),Aphi(2,nriver),DBV(ndata,nriver)
REAL::Gate(4,nriver),ql,Zctr
! calcu
REAL::dt,sita,Bsor1,Bsor2
! zzqq
REAL::Z0(nsect,nriver),Q0(nsect,nriver),Z(nsect,nriver)
REAL::Q(nsect,nriver),V(nsect,nriver)
! r_bv
REAL::condu,condd(3)
! BARC
REAL::Bs,As,Rs,Cs
f(t10,t1,t20,t2)=0.5*(sita*(t2+t1)+(1.0-sita)*(t20+t10))
tc=dt*float(tstep)/3600.0
if(UB1(river).eq.1)Z(1,river)=condu
if(UB1(river).eq.2)Q(1,river)=condu
! ----------------------------------------------------------------------------------
! LMPR
! ----------------------------------------------------------------------------------
P(1)=condu
R(1)=0.0
call sub_sect( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river,1,Z0(1,river),&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
BB10=Bs
AA10=As
RR10=Rs
CC10=Cs
call sub_sect( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river,1,Z(1,river),&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
BB1=Bs
AA1=As
RR1=Rs
CC1=Cs
do 100 k=1,Ns(river)-1
Ik=0
do 20 i=1,Pc(river)
if(Nrc(i,river).eq.k)then
Ic=i
Ik=1
end if
20 continue
if(Ik.ne.1)then
! ------------------------------------------------------
!
!
! M点处的水面宽BARQ和水位Z
! ------------------------------------------------------
call sub_sect( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river,k+1,Z0(k+1,river),&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
BB20=Bs
AA20=As
RR20=Rs
CC20=Cs
call sub_sect( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river,k+1,Z(k+1,river),&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
BB2=Bs
AA2=As
RR2=Rs
CC2=Cs
Bm=f(BB10,BB1,BB20,BB2)
Am=f(AA10,AA1,AA20,AA2)
Rm=f(RR10,RR1,RR20,RR2)
Cm=f(CC10,CC1,CC20,CC2)
Qm=f(Q0(k,river),Q(k,river),Q0(k+1,river),Q(k+1,river))
Zm=f(Z0(k,river),Z(k,river),Z0(k+1,river),Z(k+1,river))
! ------------------------------------------------------
!
! ------------------------------------------------------
a1=1.0
c1=2.0*sita*dt/(ds(k,river)*Bm)
e1=Z0(k,river)+Z0(k+1,river)+(1.0-sita)/sita*c1*(Q0(k,river)&
-Q0(k+1,river))+2.0*dt*ql/Bm
a2=2.0*sita*dt/ds(k,river)*((Qm/Am)**2.0*Bm-9.8*Am)
c2=1.0-4.0*sita*dt/ds(k,river)*Qm/Am
d2=1.0+4.0*sita*dt/ds(k,river)*Qm/Am
call sub_sect( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river,k,Zm,&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
AZm1=As
call sub_sect( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river,k+1,Zm,&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
AZm2=As
e2=(1.0-sita)/sita*a2*(Z0(k+1,river)-Z0(k,river))+(1.0-4.0*&
(1.0-sita)*dt/ds(k,river)*Qm/Am)*Q0(k+1,river)+(1.0+4.0*&
(1.0-sita)*dt/ds(k,river)*Qm/Am)*Q0(k,river)+2.0*dt*&
(Qm/Am)**2.0*(AZm2-AZm1)/ds(k,river)-2.0*dt*9.8*abs(Qm)*Qm&
/(Am*Cm*Cm*Rm)
else
! --------------------------------------------------------
! Lc=1Lc=2Lc=3
! --------------------------------------------------------
if(Lc(Ic,river).eq.1)then
do 35 j=1,nriver
if(NUB(1,j).eq.river.and.NUB(2,j).eq.Nrc(Ic,river))then
a1=0.0
c1=1.0
e1=Dric(Ic,river)*Q(1,j)
a2=1.0
c2=0.0
d2=0.0
e2=0.0
elseif(NDB(1,j).eq.river.and.NDB(2,j).eq.Nrc(Ic,river))then
a1=0.0
c1=1.0
e1=Dric(Ic,river)*Q(Ns(j),j)
a2=1.0
c2=0.0
d2=0.0
e2=0.0
end if
35 continue
elseif(Lc(Ic,river).eq.2)then
do 55 ii=1,ndata
Qjj(ii)=Qj(ii,Ic,river)
55 continue
call int_a(tc,ndata,Qjj,fc)
a1=0.0
c1=1.0
e1=Dric(Ic,river)*fc
a2=1.0
c2=0.0
d2=0.0
e2=0.0
elseif(Lc(Ic,river).eq.3)then
a1=0.5*Asave(Ic,river)/dt
c1=1.0
e1=Asave(Ic,river)*Z0(k,river)/dt
a2=1.0
c2=0.0
d2=0.0
e2=0.0
end if
end if
! ------------------------------------------------------
! 线
! ------------------------------------------------------
if(UB1(river).eq.1)then
Y1=a1*R(k)-c1
Y2=a2*R(k)+c2
Y3=e1-a1*P(k)
Y4=e2-a2*P(k)
Y5=a1*Y2+a2*Y1
L(k+1)=(a2*Y3+a1*Y4)/Y5
M(k+1)=-(a1*d2+a2*c1)/Y5
P(k+1)=(Y2*Y3-Y1*Y4)/Y5
R(k+1)=(d2*Y1-c1*Y2)/Y5
end if
! ------------------------------------------------------
! 线
! ------------------------------------------------------
if(UB1(river).eq.2)then
Y1=a1-c1*R(k)
Y2=a2+c2*R(k)
Y3=e1+c1*P(k)
Y4=e2-c2*P(k)
Y5=d2*Y1-c1*Y2
L(k+1)=(d2*Y3-c1*Y4)/Y5
M(k+1)=-(a1*d2+a2*c1)/Y5
P(k+1)=(Y1*Y4-Y2*Y3)/Y5
R(k+1)=(a1*Y2+a2*Y1)/Y5
end if
BB10=BB20
AA10=AA20
RR10=RR20
CC10=CC20
BB1=BB2
AA1=AA2
RR1=RR2
CC1=CC2
100 continue
! ----------------------------------------------------------------------------------
! Q和水位Z
! ----------------------------------------------------------------------------------
if(UB1(river).eq.1)then
Q(Ns(river),river)=(condd(3)-condd(1)*P(Ns(river)))&
/(condd(1)*R(Ns(river))+condd(2))
do 120 i=Ns(river),2,-1
Z(i,river)=P(i)+R(i)*Q(i,river)
Q(i-1,river)=L(i)+M(i)*Q(i,river)
120 continue
end if
if(UB1(river).eq.2)then
Z(Ns(river),river)=(condd(3)-condd(2)*P(Ns(river)))&
/(condd(2)*R(Ns(river))+condd(1))
do 130 i=Ns(river),2,-1
Q(i,river)=P(i)+R(i)*Z(i,river)
Z(i-1,river)=L(i)+M(i)*Z(i,river)
130 continue
end if
return
end

46
Fortran/SUB_SECT.f90 Normal file
View File

@ -0,0 +1,46 @@
! ==================================================================================
!
! ==================================================================================
subroutine sub_sect( NRIVER ,&
NSECT ,&
MRIVER ,&
KRC ,&
NDATA ,&
river ,&
Is ,&
Zs ,&
ds ,&
bd ,&
zd ,&
sm ,&
rough ,&
Bs ,&
As ,&
Rs ,&
Cs )
INTEGER::NRIVER
INTEGER::NSECT
INTEGER::MRIVER
INTEGER::KRC
INTEGER::NDATA
integer River
! section
REAL::ds(mriver,nriver),bd(nsect,nriver),zd(nsect,nriver)
REAL::sm(nsect,nriver), rough(nsect,nriver)
! BARC
REAL::Bs,As,Rs,Cs
! ----------------------------------------------------------------------------------
! BsAsRsCsZs的断面要素
! ----------------------------------------------------------------------------------
h=Zs-zd(Is,river)
Bs=bd(Is,river)+2.0*sm(Is,river)*h
As=(bd(Is,river)+sm(Is,river)*h)*h
Sl=bd(Is,river)+2*h*sqrt(1+sm(Is,river)**2.0)
Rs=As/Sl
Cs=Rs**(1.0/6.0)/rough(Is,river)
return
end

0
Fortran/~$1.xlsx Normal file
View File

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,49 @@
@FortranWebApi_HostAddress = http://localhost:5000
### 测试Fortran请求
POST {{FortranWebApi_HostAddress}}/FortranCalculate
Content-Type: application/json
{
"text": "{\"FuncName\":\"calculate_main\",\"ClassName\":\"\",\"Par\":[ {"Name":"nriver","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"nsect","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"krc","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"ndata","DataType":"0","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"Ns","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"Pc","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"Nrc","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"Lc","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"Dric","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"XJ","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"Asave","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"ds","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"bd","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"zd","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"sm","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"rough","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"ZZ0","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"Zctr","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"Qp","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"UB1","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"UB2","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"DB1","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"DB2","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"UBV","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"NUB","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"DBV","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"Gate","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"NDB","DataType":"0","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"Aphi","DataType":"1","ArrayType":"1","IsOut":"2","Data":[]},
{"Name":"period","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"dt","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"sita","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"sorz","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"sorq","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"epsz","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"epsq","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"Bsor1","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"Bsor2","DataType":"1","ArrayType":"0","IsOut":"2","Data":0},
{"Name":"Z","DataType":"1","ArrayType":"1","IsOut":"1","Data":[]},
{"Name":"Q","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,627 @@
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 == "libMAIN_UFRN.so")
{
// 尝试从当前目录加载
string currentDir = Directory.GetCurrentDirectory();
string libraryPath = Path.Combine(currentDir, "libMAIN_UFRN.so");
if (File.Exists(libraryPath))
{
return NativeLibrary.Load(libraryPath);
}
}
// 回退到默认加载行为
return IntPtr.Zero;
});
}
// DllImport声明
[DllImport("libMAIN_UFRN.so", CallingConvention = CallingConvention.Cdecl, EntryPoint = "MAIN_UFRN")]
private static extern void MAIN_UFRN(
ref int nriver,
ref int nsect,
ref int krc,
ref int ndata,
int[] Ns,
int[] Pc,
int[] Nrc,
int[] Lc,
float[] Dric,
float[] XJ,
float[] Asave,
float[] ds,
float[] bd,
float[] zd,
float[] sm,
float[] rough,
ref float ZZ0,
ref float Zctr,
float[] Qp,
int[] UB1,
int[] UB2,
int[] DB1,
int[] DB2,
float[] UBV,
int[] NUB,
float[] DBV,
float[] Gate,
int[] NDB,
float[] Aphi,
ref float period,
ref float dt,
ref float sita,
ref float sorz,
ref float sorq,
ref float epsz,
ref float epsq,
ref float Bsor1,
ref float Bsor2,
float[] Z,
float[] Q
);
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 nriver = GetIntParameter(parameters, "nriver");
int nsect = GetIntParameter(parameters, "nsect");
int krc = GetIntParameter(parameters, "krc");
int ndata = GetIntParameter(parameters, "ndata");
int[] Ns = GetIntArrayParameter(parameters, "Ns");
int[] Pc = GetIntArrayParameter(parameters, "Pc");
int[] Nrc = GetIntArrayParameter(parameters, "Nrc");
int[] Lc = GetIntArrayParameter(parameters, "Lc");
float[] Dric = GetFloatArrayParameter(parameters, "Dric");
float[] XJ = GetFloatArrayParameter(parameters, "XJ");
float[] Asave = GetFloatArrayParameter(parameters, "Asave");
float[] ds = GetFloatArrayParameter(parameters, "ds");
float[] bd = GetFloatArrayParameter(parameters, "bd");
float[] zd = GetFloatArrayParameter(parameters, "zd");
float[] sm = GetFloatArrayParameter(parameters, "sm");
float[] rough = GetFloatArrayParameter(parameters, "rough");
float ZZ0 = GetFloatParameter(parameters, "ZZ0");
float Zctr = GetFloatParameter(parameters, "Zctr");
float[] Qp = GetFloatArrayParameter(parameters, "Qp");
int[] UB1 = GetIntArrayParameter(parameters, "UB1");
int[] UB2 = GetIntArrayParameter(parameters, "UB2");
int[] DB1 = GetIntArrayParameter(parameters, "DB1");
int[] DB2 = GetIntArrayParameter(parameters, "DB2");
float[] UBV = GetFloatArrayParameter(parameters, "UBV");
int[] NUB = GetIntArrayParameter(parameters, "NUB");
float[] DBV = GetFloatArrayParameter(parameters, "DBV");
float[] Gate = GetFloatArrayParameter(parameters, "Gate");
int[] NDB = GetIntArrayParameter(parameters, "NDB");
float[] Aphi = GetFloatArrayParameter(parameters, "Aphi");
float period = GetFloatParameter(parameters, "period");
float dt = GetFloatParameter(parameters, "dt");
float sita = GetFloatParameter(parameters, "sita");
float sorz = GetFloatParameter(parameters, "sorz");
float sorq = GetFloatParameter(parameters, "sorq");
float epsz = GetFloatParameter(parameters, "epsz");
float epsq = GetFloatParameter(parameters, "epsq");
float Bsor1 = GetFloatParameter(parameters, "Bsor1");
float Bsor2 = GetFloatParameter(parameters, "Bsor2");
// 准备数组参数
float[] Z = new float[10000]; // 输出数组初始大小为10000
float[] Q = new float[10000]; // 输出数组初始大小为10000
// 调用Fortran函数
MAIN_UFRN(
ref nriver,
ref nsect,
ref krc,
ref ndata,
Ns,
Pc,
Nrc,
Lc,
Dric,
XJ,
Asave,
ds,
bd,
zd,
sm,
rough,
ref ZZ0,
ref Zctr,
Qp,
UB1,
UB2,
DB1,
DB2,
UBV,
NUB,
DBV,
Gate,
NDB,
Aphi,
ref period,
ref dt,
ref sita,
ref sorz,
ref sorq,
ref epsz,
ref epsq,
ref Bsor1,
ref Bsor2,
Z,
Q
);
// 更新输出参数
UpdateParameter(parameters, "Z", Z);
UpdateParameter(parameters, "Q", Q);
// 处理输出数组
// 处理输出数组 Z
// 注意:没有找到明确的长度参数,使用非零元素数量
{
int nonZeroCount = 0;
for (int i = 0; i < Z.Length; i++)
{
if (Z[i] != 0) nonZeroCount = i + 1;
}
if (nonZeroCount > 0)
{
float[] resultArray = new float[nonZeroCount];
Array.Copy(Z, resultArray, nonZeroCount);
UpdateArrayParameter(parameters, "Z", resultArray);
}
}
// 处理输出数组 Q
// 注意:没有找到明确的长度参数,使用非零元素数量
{
int nonZeroCount = 0;
for (int i = 0; i < Q.Length; i++)
{
if (Q[i] != 0) nonZeroCount = i + 1;
}
if (nonZeroCount > 0)
{
float[] resultArray = new float[nonZeroCount];
Array.Copy(Q, resultArray, nonZeroCount);
UpdateArrayParameter(parameters, "Q", 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"
}
}
}
}