Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a38dba5728 | ||
| 083e5dac5b | |||
| 622d9837fd | |||
| 655abebe52 | |||
| 18a9d70698 | |||
|
|
aaa597c52e | ||
|
|
571302a86b | ||
|
71e861e417
|
|||
|
|
bec03ed5ec | ||
| 75ba2abcfe | |||
|
0c55b2dcbd
|
|||
|
|
c9b3320464 | ||
|
|
bfb3a8e489 | ||
|
8715f4d8c3
|
|||
|
c89f35bc6e
|
|||
|
|
c22ae77301 | ||
| c4513c0b09 | |||
| 06a4aeabf1 | |||
|
|
65fbf66016 | ||
| bfbaa3aeff | |||
| ad148f6284 | |||
| 33b7b999c8 | |||
|
|
80f538fcb0 | ||
| 6b16e07adc | |||
| 2e87294c46 |
@@ -18,7 +18,7 @@ let versionFile = Path.getFullName ".version"
|
||||
Target.create "Clean" (fun _ -> Shell.cleanDir distPath)
|
||||
|
||||
Target.create "InstallClient" (fun _ ->
|
||||
run npm "install" "."
|
||||
run bun "install" "."
|
||||
run dotnet "tool restore" "."
|
||||
)
|
||||
|
||||
|
||||
@@ -72,16 +72,16 @@ let createProcess exe arg dir =
|
||||
|> CreateProcess.ensureExitCode
|
||||
|
||||
let dotnet = createProcess "dotnet"
|
||||
let npm =
|
||||
let npmPath =
|
||||
match ProcessUtils.tryFindFileOnPath "npm" with
|
||||
let bun =
|
||||
let bunPath =
|
||||
match ProcessUtils.tryFindFileOnPath "bun" with
|
||||
| Some path -> path
|
||||
| None ->
|
||||
"npm was not found in path. Please install it and make sure it's available from your path. " +
|
||||
"bun was not found in path. Please install it and make sure it's available from your path. " +
|
||||
"See https://safe-stack.github.io/docs/quickstart/#install-pre-requisites for more info"
|
||||
|> failwith
|
||||
|
||||
createProcess npmPath
|
||||
createProcess bunPath
|
||||
|
||||
let run proc arg dir =
|
||||
proc arg dir
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fantomas": {
|
||||
"version": "7.0.1",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
],
|
||||
"rollForward": false
|
||||
},
|
||||
"dotnet-outdated-tool": {
|
||||
"version": "4.6.7",
|
||||
"commands": [
|
||||
"dotnet-outdated"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,32 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0
|
||||
|
||||
# Add keys and sources lists
|
||||
RUN apt-get update && apt-get install -y ca-certificates gnupg
|
||||
RUN mkdir -p /etc/apt/keyrings
|
||||
RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
|
||||
ENV NODE_MAJOR=20
|
||||
RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list
|
||||
# Bun version
|
||||
ARG BUN_INSTALL=/usr/local
|
||||
ARG BUN_VERSION=bun-v1.2.16
|
||||
|
||||
# Install node, 7zip, git, process tools
|
||||
# Install node, 7zip, yarn, git, process tools
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y nodejs p7zip-full git procps ssh-client
|
||||
&& apt-get install -y p7zip-full git procps ssh-client unzip
|
||||
|
||||
# Install Bun
|
||||
RUN set -eux; \
|
||||
curl -fsSL https://bun.sh/install > /usr/local/bin/install-bun \
|
||||
&& chmod +x /usr/local/bin/install-bun \
|
||||
&& /usr/local/bin/install-bun $BUN_VERSION debug-info
|
||||
|
||||
ENV BUN_INSTALL=/usr/local
|
||||
|
||||
# Clean up
|
||||
RUN apt-get autoremove -y \
|
||||
&& apt-get clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install dotnet tools
|
||||
RUN dotnet tool install fable -g
|
||||
|
||||
# Trouble brewing
|
||||
RUN rm /etc/ssl/openssl.cnf
|
||||
|
||||
# add dotnet tools to path to pick up fake and paket installation
|
||||
# Add dotnet tools to path to pick up fake and paket installation
|
||||
ENV PATH="/root/.dotnet/tools:${PATH}"
|
||||
|
||||
# Copy endpoint specific user settings into container to specify
|
||||
# .NET Core should be used as the runtime.
|
||||
COPY settings.vscode.json /root/.vscode-remote/data/Machine/settings.json
|
||||
COPY settings.vscode.json /root/.vscode-remote/data/Machine/settings.json
|
||||
|
||||
@@ -11,6 +11,10 @@ insert_final_newline = false
|
||||
indent_size = 2
|
||||
max_line_length= 80
|
||||
|
||||
[*.nix]
|
||||
indent_size = 2
|
||||
max_line_length= 80
|
||||
|
||||
[*.fs]
|
||||
max_line_length= 120
|
||||
|
||||
@@ -21,6 +25,7 @@ fsharp_space_before_uppercase_invocation = true
|
||||
fsharp_blank_lines_around_nested_multiline_expressions = false
|
||||
fsharp_newline_between_type_definition_and_members = false
|
||||
fsharp_multiline_bracket_style = stroustrup
|
||||
fsharp_multi_line_lambda_closing_newline = true
|
||||
|
||||
fsharp_array_or_list_multiline_formatter = character_width
|
||||
fsharp_max_array_or_list_width = 70
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,4 +15,6 @@ deploy
|
||||
.ionide/
|
||||
*.db
|
||||
build.fsx.lock
|
||||
dist/
|
||||
dist/
|
||||
.direnv/
|
||||
result*
|
||||
@@ -1,8 +1,11 @@
|
||||
variables:
|
||||
DEPLOY_NAME: fvcomkit
|
||||
SDK_VERSION: 9.0
|
||||
SKIP_TESTS: "true"
|
||||
|
||||
include:
|
||||
- project: oceanbox/gitlab-ci
|
||||
ref: v2
|
||||
file: DotnetPackage.gitlab-ci.yml
|
||||
ref: v4.1
|
||||
file: DotnetPackage.gitlab-ci.yml
|
||||
inputs:
|
||||
project-name: oceanbox.fvcomkit
|
||||
project-dir: .
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27004.2005
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C29C6F32-3A30-4071-9B4A-8FBCAAA5993A}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
LICENSE = LICENSE
|
||||
shell.nix = shell.nix
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Build", "Build.fsproj", "{C6824583-FB68-4F69-8117-6B29637A3B96}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "src", "src/Oceanbox.FvcomKit.fsproj", "{662A0CDC-7E82-4157-AD25-469DD7ABAA69}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "test", "test\Tests.fsproj", "{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "submodules", "submodules", "{F8275720-F8B1-43A2-B04D-4306D71CC340}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C6824583-FB68-4F69-8117-6B29637A3B96}.Release|x86.Build.0 = Release|Any CPU
|
||||
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Release|x64.Build.0 = Release|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{662A0CDC-7E82-4157-AD25-469DD7ABAA69}.Release|x86.Build.0 = Release|Any CPU
|
||||
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Release|x64.Build.0 = Release|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{BCBD73E2-7170-4A85-BFD8-B76F056D4D49}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {79A6998D-BCE6-4EC5-ADBC-69234C0D2EC5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
16
Oceanbox.FvcomKit.slnx
Normal file
16
Oceanbox.FvcomKit.slnx
Normal file
@@ -0,0 +1,16 @@
|
||||
<Solution>
|
||||
<Configurations>
|
||||
<Platform Name="Any CPU" />
|
||||
<Platform Name="x64" />
|
||||
<Platform Name="x86" />
|
||||
</Configurations>
|
||||
<Folder Name="/Solution Items/">
|
||||
<File Path="LICENSE" />
|
||||
<File Path="README.md" />
|
||||
<File Path="shell.nix" />
|
||||
</Folder>
|
||||
<Folder Name="/submodules/" />
|
||||
<Project Path="Build.fsproj" />
|
||||
<Project Path="src/Oceanbox.FvcomKit.fsproj" />
|
||||
<Project Path="xtest/xtest.fsproj" />
|
||||
</Solution>
|
||||
@@ -1,5 +1,60 @@
|
||||
# Changelog
|
||||
|
||||
# [6.0.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.13.0...v6.0.0) (2026-01-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Update Arome to translate latlon to lambert ([655abeb](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/655abebe526a3587c26429e41130d78f326fa524))
|
||||
|
||||
# [5.13.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.12.2...v5.13.0) (2025-11-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add ElemsAroundElem to NeighborIndex ([71e861e](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/71e861e4174a57d11cfd85ac04f69c51fc985b4c))
|
||||
|
||||
## [5.12.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.12.1...v5.12.2) (2025-09-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Bump Oceanbox.SDSLite to 2.8.0 and use bun for SR ([0c55b2d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/0c55b2dcbdb89337abdbe430a30461d09dbb0bd2))
|
||||
|
||||
## [5.12.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.12.0...v5.12.1) (2025-05-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* include edge point in isInsideTriangle ([c89f35b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/c89f35bc6e316ac19d2de4ef35dbb78302881373))
|
||||
* remove unused double precision function ([8715f4d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8715f4d8c32d04f6d1c77502435234dadd0863ae))
|
||||
|
||||
# [5.12.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.11.0...v5.12.0) (2025-03-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add Grid.toLonLat function ([06a4aea](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/06a4aeabf1bcd2824db74a1851f0703797fdacf8))
|
||||
|
||||
# [5.11.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.10.0...v5.11.0) (2025-03-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* init sha once explicitly from sha1 byte[] ([33b7b99](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/33b7b999c8aaff3190dbe8a5e4d3f2e8e1cbf15e))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* rename grid sha1 to hash for better generality ([bfbaa3a](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/bfbaa3aeff66b39526cf817009729df3fe4966cc))
|
||||
|
||||
# [5.10.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.9.1...v5.10.0) (2025-03-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* init sha once explicitly from bingrid ([2e87294](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/2e87294c46579b35096c80b50bc16b89a1352b93))
|
||||
|
||||
## [5.9.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.9.0...v5.9.1) (2025-03-06)
|
||||
|
||||
|
||||
|
||||
302
bun.lock
Normal file
302
bun.lock
Normal file
@@ -0,0 +1,302 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 0,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@semantic-release/changelog": "^6.0.1",
|
||||
"@semantic-release/exec": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@semantic-release/gitlab": "^7.0.4",
|
||||
"semantic-release-dotnet": "^1.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@babel/code-frame": ["@babel/code-frame@7.16.7", "", { "dependencies": { "@babel/highlight": "^7.16.7" } }, "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.16.7", "", {}, "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="],
|
||||
|
||||
"@babel/highlight": ["@babel/highlight@7.16.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||
|
||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||
|
||||
"@semantic-release/changelog": ["@semantic-release/changelog@6.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "fs-extra": "^9.0.0", "lodash": "^4.17.4" } }, "sha512-FT+tAGdWHr0RCM3EpWegWnvXJ05LQtBkQUaQRIExONoXjVjLuOILNm4DEKNaV+GAQyJjbLRVs57ti//GypH6PA=="],
|
||||
|
||||
"@semantic-release/error": ["@semantic-release/error@3.0.0", "", {}, "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw=="],
|
||||
|
||||
"@semantic-release/exec": ["@semantic-release/exec@6.0.3", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "parse-json": "^5.0.0" } }, "sha512-bxAq8vLOw76aV89vxxICecEa8jfaWwYITw6X74zzlO0mc/Bgieqx9kBRz9z96pHectiTAtsCwsQcUyLYWnp3VQ=="],
|
||||
|
||||
"@semantic-release/git": ["@semantic-release/git@10.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "micromatch": "^4.0.0", "p-reduce": "^2.0.0" } }, "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w=="],
|
||||
|
||||
"@semantic-release/gitlab": ["@semantic-release/gitlab@7.0.4", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", "escape-string-regexp": "^3.0.0", "form-data": "^4.0.0", "fs-extra": "^10.0.0", "globby": "^11.0.0", "got": "^11.0.0", "lodash": "^4.17.11", "parse-path": "^4.0.0", "url-join": "^4.0.0" } }, "sha512-TL6kT526+ir/uehMFdTlJNXUj+p+SjPAYUkit6lh5Rs8kxeHQ01bgmpYLQlc94ZDpy9x2Tzcb/NRwKojkmLG4A=="],
|
||||
|
||||
"@sindresorhus/is": ["@sindresorhus/is@4.3.0", "", {}, "sha512-wwOvh0eO3PiTEivGJWiZ+b946SlMSb4pe+y+Ur/4S87cwo09pYi+FWHHnbrM3W9W7cBYKDqQXcrFYjYUCOJUEQ=="],
|
||||
|
||||
"@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="],
|
||||
|
||||
"@types/cacheable-request": ["@types/cacheable-request@6.0.2", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "*", "@types/node": "*", "@types/responselike": "*" } }, "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA=="],
|
||||
|
||||
"@types/glob": ["@types/glob@7.2.0", "", { "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA=="],
|
||||
|
||||
"@types/http-cache-semantics": ["@types/http-cache-semantics@4.0.1", "", {}, "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="],
|
||||
|
||||
"@types/keyv": ["@types/keyv@3.1.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg=="],
|
||||
|
||||
"@types/minimatch": ["@types/minimatch@3.0.5", "", {}, "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="],
|
||||
|
||||
"@types/node": ["@types/node@17.0.9", "", {}, "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ=="],
|
||||
|
||||
"@types/responselike": ["@types/responselike@1.0.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA=="],
|
||||
|
||||
"aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||
|
||||
"array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha1-x57Zf380y48robyXkLzDZkdLS3k="],
|
||||
|
||||
"at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||
|
||||
"braces": ["braces@3.0.2", "", { "dependencies": { "fill-range": "^7.0.1" } }, "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="],
|
||||
|
||||
"cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="],
|
||||
|
||||
"cacheable-request": ["cacheable-request@7.0.2", "", { "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew=="],
|
||||
|
||||
"call-bind": ["call-bind@1.0.2", "", { "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" } }, "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="],
|
||||
|
||||
"chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
|
||||
|
||||
"clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
|
||||
|
||||
"clone-response": ["clone-response@1.0.2", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws="],
|
||||
|
||||
"color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
||||
|
||||
"color-name": ["color-name@1.1.3", "", {}, "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="],
|
||||
|
||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
|
||||
|
||||
"debug": ["debug@4.3.3", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q=="],
|
||||
|
||||
"decode-uri-component": ["decode-uri-component@0.2.0", "", {}, "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="],
|
||||
|
||||
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
|
||||
|
||||
"defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="],
|
||||
|
||||
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="],
|
||||
|
||||
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
|
||||
|
||||
"end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="],
|
||||
|
||||
"error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@3.0.0", "", {}, "sha512-11dXIUC3umvzEViLP117d0KN6LJzZxh5+9F4E/7WLAAw7GrHk8NpUR+g9iJi/pe9C0py4F8rs0hreyRCwlAuZg=="],
|
||||
|
||||
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||
|
||||
"fast-glob": ["fast-glob@3.2.11", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew=="],
|
||||
|
||||
"fastq": ["fastq@1.13.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw=="],
|
||||
|
||||
"fill-range": ["fill-range@7.0.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="],
|
||||
|
||||
"filter-obj": ["filter-obj@1.1.0", "", {}, "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="],
|
||||
|
||||
"form-data": ["form-data@4.0.0", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww=="],
|
||||
|
||||
"fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
|
||||
|
||||
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.1", "", {}, "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.1.1", "", { "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1" } }, "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q=="],
|
||||
|
||||
"get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
|
||||
|
||||
"glob": ["glob@7.2.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q=="],
|
||||
|
||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"glob-promise": ["glob-promise@4.2.2", "", { "dependencies": { "@types/glob": "^7.1.3" }, "peerDependencies": { "glob": "^7.1.6" } }, "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw=="],
|
||||
|
||||
"globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
|
||||
|
||||
"got": ["got@11.8.3", "", { "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", "p-cancelable": "^2.0.0", "responselike": "^2.0.0" } }, "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.9", "", {}, "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="],
|
||||
|
||||
"has": ["has@1.0.3", "", { "dependencies": { "function-bind": "^1.1.1" } }, "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="],
|
||||
|
||||
"has-flag": ["has-flag@3.0.0", "", {}, "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="],
|
||||
|
||||
"has-symbols": ["has-symbols@1.0.2", "", {}, "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="],
|
||||
|
||||
"http-cache-semantics": ["http-cache-semantics@4.1.0", "", {}, "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="],
|
||||
|
||||
"http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="],
|
||||
|
||||
"human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
|
||||
|
||||
"ignore": ["ignore@5.2.0", "", {}, "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="],
|
||||
|
||||
"indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="],
|
||||
|
||||
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-ssh": ["is-ssh@1.3.3", "", { "dependencies": { "protocols": "^1.1.0" } }, "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ=="],
|
||||
|
||||
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||
|
||||
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
|
||||
|
||||
"jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="],
|
||||
|
||||
"keyv": ["keyv@4.0.5", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-531pkGLqV3BMg0eDqqJFI0R1mkK1Nm5xIP2mM6keP5P8WfFtCkg2IOwplTUmlGoTgIg9yQYZ/kdihhz89XH3vA=="],
|
||||
|
||||
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||
|
||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="],
|
||||
|
||||
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
|
||||
|
||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||
|
||||
"micromatch": ["micromatch@4.0.4", "", { "dependencies": { "braces": "^3.0.1", "picomatch": "^2.2.3" } }, "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg=="],
|
||||
|
||||
"mime-db": ["mime-db@1.51.0", "", {}, "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="],
|
||||
|
||||
"mime-types": ["mime-types@2.1.34", "", { "dependencies": { "mime-db": "1.51.0" } }, "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A=="],
|
||||
|
||||
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
|
||||
|
||||
"minimatch": ["minimatch@3.0.4", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA=="],
|
||||
|
||||
"ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
|
||||
|
||||
"normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="],
|
||||
|
||||
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"object-inspect": ["object-inspect@1.12.0", "", {}, "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha1-WDsap3WWHUsROsF9nFC6753Xa9E="],
|
||||
|
||||
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="],
|
||||
|
||||
"p-reduce": ["p-reduce@2.1.0", "", {}, "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw=="],
|
||||
|
||||
"parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
|
||||
|
||||
"parse-path": ["parse-path@4.0.3", "", { "dependencies": { "is-ssh": "^1.3.0", "protocols": "^1.4.0", "qs": "^6.9.4", "query-string": "^6.13.8" } }, "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA=="],
|
||||
|
||||
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
||||
|
||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"protocols": ["protocols@1.4.8", "", {}, "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg=="],
|
||||
|
||||
"pump": ["pump@3.0.0", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww=="],
|
||||
|
||||
"qs": ["qs@6.10.3", "", { "dependencies": { "side-channel": "^1.0.4" } }, "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ=="],
|
||||
|
||||
"query-string": ["query-string@6.14.1", "", { "dependencies": { "decode-uri-component": "^0.2.0", "filter-obj": "^1.1.0", "split-on-first": "^1.0.0", "strict-uri-encode": "^2.0.0" } }, "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw=="],
|
||||
|
||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||
|
||||
"quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="],
|
||||
|
||||
"resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="],
|
||||
|
||||
"responselike": ["responselike@2.0.0", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw=="],
|
||||
|
||||
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
"sax": ["sax@1.2.4", "", {}, "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="],
|
||||
|
||||
"semantic-release-dotnet": ["semantic-release-dotnet@1.0.0", "", { "dependencies": { "glob": "^7.1.7", "glob-promise": "^4.2.0", "xml-js": "^1.6.11" } }, "sha512-U/cHwqqzFbJpPCQ/KMTSZtwzPNWCNCVStZRznMGK0xjhiLoDfRe5KFRs/9dzWBtPa358D7IiVzz97ZzepUAtfQ=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"side-channel": ["side-channel@1.0.4", "", { "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", "object-inspect": "^1.9.0" } }, "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw=="],
|
||||
|
||||
"signal-exit": ["signal-exit@3.0.6", "", {}, "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="],
|
||||
|
||||
"slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
|
||||
|
||||
"split-on-first": ["split-on-first@1.1.0", "", {}, "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="],
|
||||
|
||||
"strict-uri-encode": ["strict-uri-encode@2.0.0", "", {}, "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="],
|
||||
|
||||
"strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
||||
|
||||
"supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"universalify": ["universalify@2.0.0", "", {}, "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="],
|
||||
|
||||
"url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="],
|
||||
|
||||
"xml-js": ["xml-js@1.6.11", "", { "dependencies": { "sax": "^1.2.4" }, "bin": "bin/cli.js" }, "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g=="],
|
||||
|
||||
"@semantic-release/gitlab/fs-extra": ["fs-extra@10.0.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ=="],
|
||||
|
||||
"cacheable-request/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
||||
|
||||
"chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="],
|
||||
|
||||
"clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
|
||||
}
|
||||
}
|
||||
19
default.nix
Normal file
19
default.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
sources ? import ./nix,
|
||||
system ? builtins.currentSystem,
|
||||
pkgs ? import sources.nixpkgs {
|
||||
inherit system;
|
||||
config = { };
|
||||
overlays = [ ];
|
||||
},
|
||||
}:
|
||||
let
|
||||
sdk = pkgs.dotnetCorePackages.sdk_9_0;
|
||||
sdslite = pkgs.callPackage ./nix/sdslite.nix { dotnet-sdk = sdk; };
|
||||
projnetFsharp = pkgs.callPackage ./nix/projnet.fsharp.nix { dotnet-sdk = sdk; };
|
||||
in
|
||||
pkgs.callPackage ./src {
|
||||
SDSLite = sdslite;
|
||||
projnet = projnetFsharp;
|
||||
dotnet-sdk = sdk;
|
||||
}
|
||||
146
nix/default.nix
Normal file
146
nix/default.nix
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
This file is provided under the MIT licence:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
# Generated by npins. Do not modify; will be overwritten regularly
|
||||
let
|
||||
data = builtins.fromJSON (builtins.readFile ./sources.json);
|
||||
version = data.version;
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
|
||||
range =
|
||||
first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
|
||||
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
|
||||
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
|
||||
concatMapStrings = f: list: concatStrings (map f list);
|
||||
concatStrings = builtins.concatStringsSep "";
|
||||
|
||||
# If the environment variable NPINS_OVERRIDE_${name} is set, then use
|
||||
# the path directly as opposed to the fetched source.
|
||||
# (Taken from Niv for compatibility)
|
||||
mayOverride =
|
||||
name: path:
|
||||
let
|
||||
envVarName = "NPINS_OVERRIDE_${saneName}";
|
||||
saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name;
|
||||
ersatz = builtins.getEnv envVarName;
|
||||
in
|
||||
if ersatz == "" then
|
||||
path
|
||||
else
|
||||
# this turns the string into an actual Nix path (for both absolute and
|
||||
# relative paths)
|
||||
builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" (
|
||||
if builtins.substring 0 1 ersatz == "/" then
|
||||
/. + ersatz
|
||||
else
|
||||
/. + builtins.getEnv "PWD" + "/${ersatz}"
|
||||
);
|
||||
|
||||
mkSource =
|
||||
name: spec:
|
||||
assert spec ? type;
|
||||
let
|
||||
path =
|
||||
if spec.type == "Git" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "GitRelease" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "PyPi" then
|
||||
mkPyPiSource spec
|
||||
else if spec.type == "Channel" then
|
||||
mkChannelSource spec
|
||||
else if spec.type == "Tarball" then
|
||||
mkTarballSource spec
|
||||
else
|
||||
builtins.throw "Unknown source type ${spec.type}";
|
||||
in
|
||||
spec // { outPath = mayOverride name path; };
|
||||
|
||||
mkGitSource =
|
||||
{
|
||||
repository,
|
||||
revision,
|
||||
url ? null,
|
||||
submodules,
|
||||
hash,
|
||||
branch ? null,
|
||||
...
|
||||
}:
|
||||
assert repository ? type;
|
||||
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
||||
# In the latter case, there we will always be an url to the tarball
|
||||
if url != null && !submodules then
|
||||
builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash; # FIXME: check nix version & use SRI hashes
|
||||
}
|
||||
else
|
||||
let
|
||||
url =
|
||||
if repository.type == "Git" then
|
||||
repository.url
|
||||
else if repository.type == "GitHub" then
|
||||
"https://github.com/${repository.owner}/${repository.repo}.git"
|
||||
else if repository.type == "GitLab" then
|
||||
"${repository.server}/${repository.repo_path}.git"
|
||||
else
|
||||
throw "Unrecognized repository type ${repository.type}";
|
||||
urlToName =
|
||||
url: rev:
|
||||
let
|
||||
matched = builtins.match "^.*/([^/]*)(\\.git)?$" url;
|
||||
|
||||
short = builtins.substring 0 7 rev;
|
||||
|
||||
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
||||
in
|
||||
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
||||
name = urlToName url revision;
|
||||
in
|
||||
builtins.fetchGit {
|
||||
rev = revision;
|
||||
inherit name;
|
||||
# hash = hash;
|
||||
inherit url submodules;
|
||||
};
|
||||
|
||||
mkPyPiSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchurl {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkChannelSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkTarballSource =
|
||||
{
|
||||
url,
|
||||
locked_url ? url,
|
||||
hash,
|
||||
...
|
||||
}:
|
||||
builtins.fetchTarball {
|
||||
url = locked_url;
|
||||
sha256 = hash;
|
||||
};
|
||||
in
|
||||
if version == 5 then
|
||||
builtins.mapAttrs mkSource data.pins
|
||||
else
|
||||
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
||||
29
nix/projnet.fsharp.nix
Normal file
29
nix/projnet.fsharp.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
dotnet-sdk,
|
||||
fetchFromGitLab,
|
||||
buildDotnetModule
|
||||
}:
|
||||
let
|
||||
src = fetchFromGitLab {
|
||||
owner = "oceanbox";
|
||||
repo = "ProjNet.FSharp";
|
||||
# tag = "v5.2.0";
|
||||
rev = "722ce0c23fda6844a81e995afbb2d81cbd5f38ec";
|
||||
private = true;
|
||||
forceFetchGit = true;
|
||||
hash = "sha256-Rvnnf/D2x90pwgvTbXz307MJVBlVPK/cCf1hqj2VosE=";
|
||||
};
|
||||
in
|
||||
buildDotnetModule {
|
||||
name = "ProjNet.FSharp";
|
||||
|
||||
src = src;
|
||||
|
||||
dotnet-sdk = dotnet-sdk;
|
||||
|
||||
projectFile = "src/ProjNet.FSharp.fsproj";
|
||||
nugetDeps = "${src}/src/deps.json";
|
||||
packNupkg = true;
|
||||
|
||||
executables = [ ];
|
||||
}
|
||||
29
nix/sdslite.nix
Normal file
29
nix/sdslite.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
dotnet-sdk,
|
||||
fetchFromGitLab,
|
||||
buildDotnetModule
|
||||
}:
|
||||
let
|
||||
src = fetchFromGitLab {
|
||||
owner = "oceanbox";
|
||||
repo = "SDSlite";
|
||||
# tag = "v2.8.0";
|
||||
rev = "8c1a158206c37bc57a5bd726a792bd6a9cd2ec01";
|
||||
private = true;
|
||||
forceFetchGit = true;
|
||||
hash = "sha256-i9pNrmH/VC0Q9FCldbWGdZHkqSL1cdYtAOs7vX+DlXM=";
|
||||
};
|
||||
in
|
||||
buildDotnetModule {
|
||||
name = "Oceanbox.SDSLite";
|
||||
|
||||
src = src;
|
||||
|
||||
dotnet-sdk = dotnet-sdk;
|
||||
|
||||
projectFile = "ScientificDataSet/ScientificDataSet.csproj";
|
||||
nugetDeps = "${src}/ScientificDataSet/deps.json";
|
||||
packNupkg = true;
|
||||
|
||||
executables = [ ];
|
||||
}
|
||||
23
nix/sources.json
Normal file
23
nix/sources.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"pins": {
|
||||
"nix-utils": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "Git",
|
||||
"url": "https://git.sr.ht/~mrtz/nix-utils"
|
||||
},
|
||||
"branch": "trunk",
|
||||
"submodules": false,
|
||||
"revision": "098f594425d2b9dde0657becad0f6498d074f8b3",
|
||||
"url": null,
|
||||
"hash": "0hh52w1fkpr1xx6j8cjm6g88j2352yv2ysqm1q51j59y6f583vyb"
|
||||
},
|
||||
"nixpkgs": {
|
||||
"type": "Channel",
|
||||
"name": "nixpkgs-unstable",
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre905319.f720de590661/nixexprs.tar.xz",
|
||||
"hash": "07n4hhch0j6n69b0zchdjg0l80z2xrdk7k57ykv90cvhklim5dz1"
|
||||
}
|
||||
},
|
||||
"version": 5
|
||||
}
|
||||
4
nix/sources.nix
Normal file
4
nix/sources.nix
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"ProjNet.FSharp" = "https://gitlab.com/api/v4/projects/35009572/packages/nuget/download";
|
||||
"Oceanbox.SDSLite" = "https://gitlab.com/api/v4/projects/34025102/packages/nuget/download";
|
||||
}
|
||||
2772
package-lock.json
generated
2772
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
31
shell.nix
31
shell.nix
@@ -1,12 +1,25 @@
|
||||
with import <nixpkgs> {};
|
||||
mkShell {
|
||||
buildInputs = [
|
||||
netcdf
|
||||
nodejs
|
||||
let
|
||||
sources = import ./nix;
|
||||
pkgs = import sources.nixpkgs {};
|
||||
dotnet-sdk = pkgs.dotnetCorePackages.sdk_9_0;
|
||||
in
|
||||
with import <nixpkgs> { };
|
||||
mkShell rec {
|
||||
packages = [
|
||||
bun
|
||||
dotnet-sdk
|
||||
fsautocomplete
|
||||
fantomas
|
||||
npins
|
||||
nixfmt
|
||||
nuget-to-json
|
||||
];
|
||||
|
||||
DOTNET_ROOT = "${dotnet-sdk_8}";
|
||||
shellHook = ''
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${stdenv.cc.cc.lib}/lib;
|
||||
'';
|
||||
buildInputs = [
|
||||
netcdf
|
||||
stdenv.cc.cc.lib
|
||||
];
|
||||
|
||||
DOTNET_ROOT = "${dotnet-sdk}/share/dotnet";
|
||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
|
||||
}
|
||||
@@ -139,6 +139,7 @@ let private genOobIdx (proj: IProj) (tree: KdTree<_, _>) (cullIdx: (int * int)[]
|
||||
// cullIdx = cullIdx
|
||||
// oobIdx = genOobIdx proj tree cullIdx fPos rPos
|
||||
// }
|
||||
|
||||
let private mkFvcomAdjoint (proj: IProj) (fPos: PosVec) (bbox: BBox) ((rPos, wet): BiPos * Mask) =
|
||||
let box = mkCropBox bbox
|
||||
let pos' = reProject proj rPos
|
||||
@@ -147,7 +148,9 @@ let private mkFvcomAdjoint (proj: IProj) (fPos: PosVec) (bbox: BBox) ((rPos, wet
|
||||
let nearest =
|
||||
fPos
|
||||
|> Array.map (fun (x, y) -> tree.GetNearestNeighbours ([| x; y |], 1) |> Array.head |> (fun x -> x.Value))
|
||||
{ adjoinIdx = nearest; cullIdx = cullIdx; oobIdx = genOobIdx proj tree cullIdx fPos rPos }
|
||||
let oobIdx = genOobIdx proj tree cullIdx fPos rPos
|
||||
|
||||
{ adjoinIdx = nearest; cullIdx = cullIdx; oobIdx = oobIdx }
|
||||
|
||||
let inline float2 x = bimap float float x
|
||||
|
||||
|
||||
206
src/Arome.fs
206
src/Arome.fs
@@ -1,20 +1,76 @@
|
||||
module Oceanbox.FvcomKit.Arome
|
||||
|
||||
open FSharpPlus
|
||||
open System
|
||||
|
||||
open Microsoft.Research.Science.Data
|
||||
|
||||
open ProjNet.FSharp
|
||||
open Serilog
|
||||
|
||||
open Types
|
||||
|
||||
|
||||
let trans = makeTransform CoordSys.WGS84 (CoordSys.LCCMet ())
|
||||
|
||||
[<Struct>]
|
||||
type Pointf = {
|
||||
x: float
|
||||
y: float
|
||||
} with
|
||||
static member Zero = { x = 0.0; y = 0.0 }
|
||||
static member OfTuple (x, y) = { x = x; y = y }
|
||||
static member OfStructTuple struct (x, y) = { x = x; y = y }
|
||||
|
||||
/// Single precision
|
||||
[<Struct>]
|
||||
type Points = {
|
||||
x: single
|
||||
y: single
|
||||
} with
|
||||
static member Zero = { x = 0.0f; y = 0.0f }
|
||||
static member OfTuple (x, y) = { x = x; y = y }
|
||||
static member OfStructTuple struct (x, y) = { x = x; y = y }
|
||||
|
||||
module Pointf =
|
||||
let ofPoints (p: Points) : Pointf = { x = float p.x; y = float p.y }
|
||||
|
||||
let getBBox (points: Pointf array) : BBox =
|
||||
let minX = points |> Array.minBy _.x |> _.x
|
||||
let maxX = points |> Array.maxBy _.x |> _.x
|
||||
let minY = points |> Array.minBy _.y |> _.y
|
||||
let maxY = points |> Array.maxBy _.y |> _.y
|
||||
let center = (minX + (maxX - minX)) / 2., (minY + (maxY - minY)) / 2.
|
||||
|
||||
{
|
||||
minX = minX
|
||||
maxX = maxX
|
||||
minY = minY
|
||||
maxY = maxY
|
||||
center = center
|
||||
}
|
||||
|
||||
module Points =
|
||||
let getBBox (points: Points array) : BBox =
|
||||
let minX = points |> Array.minBy _.x |> _.x
|
||||
let maxX = points |> Array.maxBy _.x |> _.x
|
||||
let minY = points |> Array.minBy _.y |> _.y
|
||||
let maxY = points |> Array.maxBy _.y |> _.y
|
||||
let center = float (minX + (maxX - minX)) / 2., float (minY + (maxY - minY)) / 2.
|
||||
|
||||
{
|
||||
minX = float minX
|
||||
maxX = float maxX
|
||||
minY = float minY
|
||||
maxY = float maxY
|
||||
center = center
|
||||
}
|
||||
|
||||
[<Struct>]
|
||||
type SquareGrid = {
|
||||
dimensions: int * int
|
||||
BBox: BBox
|
||||
squareSize: float
|
||||
projection: ProjNet.CoordinateSystems.CoordinateSystem
|
||||
points: Points array
|
||||
} with
|
||||
member this.getBoundingBox() = this.BBox
|
||||
static member empty = {
|
||||
@@ -22,15 +78,93 @@ type SquareGrid = {
|
||||
BBox = BBox.empty
|
||||
squareSize = 0.0
|
||||
projection = CoordSys.LCCMet ()
|
||||
points = Array.empty
|
||||
}
|
||||
|
||||
let getBBox (xs: float array) (ys: float array) : BBox =
|
||||
let private square x = x * x
|
||||
|
||||
let haversineDistance (earthRadius: float) (x0: float) (y0: float) (x1: float) (y1: float) : float =
|
||||
let mutable lat1 = y0
|
||||
let mutable lat2 = y1
|
||||
let lon1 = x0
|
||||
let lon2 = x1
|
||||
|
||||
let dLat = Double.DegreesToRadians (lat2 - lat1)
|
||||
let dLon = Double.DegreesToRadians (lon2 - lon1)
|
||||
lat1 <- Double.DegreesToRadians lat1
|
||||
lat2 <- Double.DegreesToRadians lat2
|
||||
|
||||
let a = square (Math.Sin (dLat / 2.0)) + Math.Cos lat1 * Math.Cos lat2 * square (Math.Sin (dLon / 2.0))
|
||||
let c = 2.0 * Math.Asin (Math.Sqrt a)
|
||||
|
||||
let result = earthRadius * c
|
||||
|
||||
result
|
||||
|
||||
let getGrid (ds: DataSet) : Result<SquareGrid, string> =
|
||||
try
|
||||
let minX = Array.min xs
|
||||
let maxX = Array.max xs
|
||||
let minY = Array.min ys
|
||||
let maxY = Array.max ys
|
||||
let center = float (minX + (maxX - minX)) / 2., float (minY + (maxY - minY)) / 2.
|
||||
let dimensions = ds.Dimensions["x"].Length, ds.Dimensions["y"].Length
|
||||
let longs : float array2d = ds["longitude"].GetData () :?> float[,]
|
||||
let lats : float array2d = ds["latitude"].GetData () :?> float[,]
|
||||
// NOTE: The netcdf file dimensions are defined as (y, x)
|
||||
let width = Array2D.length2 longs
|
||||
let height = Array2D.length1 lats
|
||||
let points : Points array =
|
||||
let result = Array.create (width * height) Points.Zero
|
||||
for i in 0 .. height - 1 do
|
||||
for j in 0 .. width - 1 do
|
||||
let lat = lats[i, j]
|
||||
let lon = longs[i, j]
|
||||
let p = lon, lat
|
||||
// NOTE(simkir): Convert to lambert projection
|
||||
let x, y = trans.project p
|
||||
result[i * width + j] <- Points.OfTuple (single x, single y)
|
||||
result
|
||||
|
||||
let bbox = Points.getBBox points
|
||||
|
||||
if points.Length < 2 then
|
||||
Error "The dataset must contain at least 1 square"
|
||||
else
|
||||
let p0 = points[0 * width + 0]
|
||||
let p1 = points[0 * width + 1]
|
||||
let p2 = points[1 * width + 0]
|
||||
// let p3 = points[1 * width + 1]
|
||||
let x1, x0 = if p1.x > p0.x then p1.x, p0.x else p0.x, p1.x
|
||||
let y1, y0 = if p2.y > p1.y then p2.y, p1.y else p1.y, p2.y
|
||||
let lengthX = x1 - x0
|
||||
let lengthY = y1 - y0
|
||||
let isSquare = lengthX = lengthY
|
||||
|
||||
if not isSquare then
|
||||
Log.Warning (
|
||||
"FvcomKit.Arome.getGrid grid is not square: {X1} - {X0} = {LengthX} = {LengthY} = {Y1} - {Y0}",
|
||||
x1,
|
||||
x0,
|
||||
lengthX,
|
||||
lengthY,
|
||||
y1,
|
||||
y0
|
||||
)
|
||||
|
||||
Ok {
|
||||
SquareGrid.empty with
|
||||
dimensions = dimensions
|
||||
BBox = bbox
|
||||
squareSize = float lengthX
|
||||
points = points
|
||||
}
|
||||
with exn ->
|
||||
Log.Error (exn, "Sorcerer.Arome.getAromeSquareGrid exception")
|
||||
Error $"Error reading arome grid: {exn.Message}"
|
||||
|
||||
let private getBBox (xs: float array) (ys: float array) : BBox =
|
||||
try
|
||||
let minX = xs |> Array.min
|
||||
let maxX = xs |> Array.max
|
||||
let minY = ys |> Array.min
|
||||
let maxY = ys |> Array.max
|
||||
let center = (minX + (maxX - minX)) / 2., (minY + (maxY - minY)) / 2.
|
||||
|
||||
{
|
||||
minX = minX
|
||||
@@ -43,7 +177,8 @@ let getBBox (xs: float array) (ys: float array) : BBox =
|
||||
Log.Error $"{e}"
|
||||
BBox.empty
|
||||
|
||||
let getGrid (ds: DataSet) : Result<SquareGrid, string> =
|
||||
/// Depends on the netcdf having the 'x' and 'y' variables
|
||||
let getSquareGrid (ds: DataSet) : Result<SquareGrid, string> =
|
||||
try
|
||||
let dimensions = ds.Dimensions["x"].Length, ds.Dimensions["y"].Length
|
||||
let xs = (ds["x"].GetData () :?> single[]) |> Array.map float
|
||||
@@ -77,27 +212,35 @@ let getGrid (ds: DataSet) : Result<SquareGrid, string> =
|
||||
Log.Error (exn, "FvcomKit.Arome.getGrid exception")
|
||||
Error $"Error reading arome grid: {exn.Message}"
|
||||
|
||||
let readUV (ds: DataSet) t x y =
|
||||
let u = ds["x_wind_10m"].GetData ([| t; y; x |], [| 1; 1; 1 |]) :?> single[,,]
|
||||
let v = ds["y_wind_10m"].GetData ([| t; y; x |], [| 1; 1; 1 |]) :?> single[,,]
|
||||
u[0, 0, 0], v[0, 0, 0]
|
||||
let readUV (ds: DataSet) (t: int) x y : single * single =
|
||||
let xWind = ds["x_wind_10m"]
|
||||
let yWind = ds["y_wind_10m"]
|
||||
let origin = [| t; 0; y; x |]
|
||||
let shape = [| 1; 1; 1; 1; |]
|
||||
Log.Verbose("""Fetching NetCDF["x_wind_10m"]({Origin}, {Shape})""", origin, shape)
|
||||
let us = xWind.GetData (origin, shape) :?> single[,,,]
|
||||
let vs = yWind.GetData (origin, shape) :?> single[,,,]
|
||||
|
||||
us[0, 0, 0, 0], vs[0, 0, 0, 0]
|
||||
|
||||
/// Finds the index of a tile within a square grid, given its bounding box and square length
|
||||
let tryFindIndex squareSize (wide, tall) (minX, minY) (maxX, maxY) (p0, p1) =
|
||||
if (minX < p0 && p0 < maxX) && (minY < p1 && p1 < maxY) then
|
||||
let dx = p0 - minX
|
||||
let dy = p1 - minY
|
||||
let xIdx = int (dx / squareSize)
|
||||
let yIdx = int (dy / squareSize)
|
||||
let tryFindIndex (grid: SquareGrid) (x0, y0) =
|
||||
let wide, tall = grid.dimensions
|
||||
let bbox = grid.BBox
|
||||
if bbox.minX <= x0 && x0 < bbox.maxX && bbox.minY <= y0 && y0 < bbox.maxY then
|
||||
let dx = x0 - bbox.minX
|
||||
let dy = y0 - bbox.minY
|
||||
let xIdx = int (dx / grid.squareSize)
|
||||
let yIdx = int (dy / grid.squareSize)
|
||||
|
||||
if xIdx < wide && yIdx < tall then
|
||||
Some (xIdx, yIdx)
|
||||
else
|
||||
Log.Warning (
|
||||
"Got wrong indices within the bounding box of the archive: min {@Min}, max {@Max}, point {@Point}, delta {@Delta}m, indices {@Indices}",
|
||||
(minX, minY),
|
||||
(maxX, maxY),
|
||||
(p0, p1),
|
||||
(bbox.minX, bbox.minY),
|
||||
(bbox.maxX, bbox.maxY),
|
||||
(x0, y0),
|
||||
(dx, dy),
|
||||
(xIdx, yIdx)
|
||||
)
|
||||
@@ -106,17 +249,12 @@ let tryFindIndex squareSize (wide, tall) (minX, minY) (maxX, maxY) (p0, p1) =
|
||||
None
|
||||
|
||||
/// Tries to get the closest x and y in the arome dataset based on position p
|
||||
let tryFind (grid: SquareGrid) (p0: float, p1: float) : (int * int) option =
|
||||
let min = (grid.BBox.minX, grid.BBox.minY)
|
||||
let max = (grid.BBox.maxX, grid.BBox.maxY)
|
||||
let tryFind (grid: SquareGrid) (p: float * float) : (int * int) option =
|
||||
tryFindIndex grid p
|
||||
|
||||
let tryFindWithProj (proj: Projection) (grid: SquareGrid) (p0: float, p1: float) : (int * int) option =
|
||||
let coordSys : ProjNet.CoordinateSystems.CoordinateSystem = Projection.ToCoordinateSystem proj
|
||||
let trans = makeTransform coordSys grid.projection
|
||||
let p = trans.project ((p0, p1))
|
||||
|
||||
tryFindIndex grid.squareSize grid.dimensions min max p
|
||||
|
||||
let tryFindWithProj (grid: SquareGrid) proj (p0: float, p1: float) : (int * int) option =
|
||||
let trans = Transform.makeTransform proj grid.projection
|
||||
let min = (grid.BBox.minX, grid.BBox.minY)
|
||||
let max = (grid.BBox.maxX, grid.BBox.maxY)
|
||||
let p = trans.project ((p0, p1))
|
||||
|
||||
tryFindIndex grid.squareSize grid.dimensions min max p
|
||||
tryFindIndex grid p
|
||||
@@ -29,6 +29,7 @@ type FvcomGrid = {
|
||||
member this.getVertices() = this.Nodes
|
||||
member this.getCells() = this.Elem
|
||||
member this.getBoundingBox() = this.BBox
|
||||
|
||||
static member empty = {
|
||||
Elem = Array.empty
|
||||
Nodes = Array.empty
|
||||
@@ -39,6 +40,7 @@ type FvcomGrid = {
|
||||
SiglayCenter = Array2D.zeroCreate 0 0
|
||||
Siglev = Array2D.zeroCreate 0 0
|
||||
}
|
||||
|
||||
member this.ToGrid() = { Elem = this.Elem; Nodes = this.Nodes; BBox = this.BBox }
|
||||
|
||||
let getNumFrames (ds: DataSet) =
|
||||
@@ -76,7 +78,7 @@ let getTimeSpanSinceStart (ds: DataSet) n =
|
||||
let days = ds["Itime"].GetData () :?> int[]
|
||||
let msec = ds["Itime2"].GetData () :?> int[]
|
||||
let t0 = TimeSpan.FromDays days[n]
|
||||
let t1 = TimeSpan.FromMilliseconds msec[n]
|
||||
let t1 = TimeSpan.FromMilliseconds (float msec[n])
|
||||
t0 + t1 |> Some
|
||||
with e ->
|
||||
Log.Error $"getTimeInDays exception: {e.Message}"
|
||||
@@ -526,7 +528,7 @@ module Singular =
|
||||
Log.Error $"{err}"
|
||||
0f, 0f
|
||||
|
||||
let readTemp (ds: DataSet) n t d =
|
||||
let readTemp (ds: DataSet) n t d : single =
|
||||
try
|
||||
let t = ds["temp"].GetData ([| t; d; n |], [| 1; 1; 1 |]) :?> single[,,]
|
||||
t[0, 0, 0]
|
||||
|
||||
398
src/Grid.fs
398
src/Grid.fs
@@ -9,7 +9,7 @@ open ProjNet.FSharp
|
||||
open MessagePack
|
||||
open MBrace.FsPickler
|
||||
//open FsKDTree
|
||||
open KdTree // C# version
|
||||
open KdTree // NOTE: C# version
|
||||
|
||||
open Types
|
||||
|
||||
@@ -21,8 +21,8 @@ type Elem = NodeIdx * NodeIdx * NodeIdx
|
||||
type Node = float * float
|
||||
|
||||
type Pos = float * float
|
||||
type Leaf<'a> = { Pos : Pos; Data : 'a }
|
||||
type Field = (float * float) []
|
||||
type Leaf<'a> = { Pos: Pos; Data: 'a }
|
||||
type Field = (float * float) array
|
||||
|
||||
type Cell = NodeIdx * NodeIdx * NodeIdx
|
||||
|
||||
@@ -30,16 +30,15 @@ type IGrid =
|
||||
abstract getVertex: int -> Vertex
|
||||
abstract getCell: int -> Cell
|
||||
abstract getCellVertices: int -> Vertex * Vertex * Vertex
|
||||
abstract getVertices: unit -> Vertex []
|
||||
abstract getCells: unit -> Cell []
|
||||
abstract getVertices: unit -> Vertex array
|
||||
abstract getCells: unit -> Cell array
|
||||
abstract getBoundingBox: unit -> BBox
|
||||
|
||||
type Grid =
|
||||
{
|
||||
Elem: Elem array
|
||||
Nodes: Node array
|
||||
BBox: BBox
|
||||
}
|
||||
type Grid = {
|
||||
Elem: Elem array
|
||||
Nodes: Node array
|
||||
BBox: BBox
|
||||
} with
|
||||
interface IGrid with
|
||||
member this.getVertex n = this.Nodes[n]
|
||||
member this.getCell n = this.Elem[n]
|
||||
@@ -49,55 +48,48 @@ type Grid =
|
||||
member this.getVertices() = this.Nodes
|
||||
member this.getCells() = this.Elem
|
||||
member this.getBoundingBox() = this.BBox
|
||||
static member empty =
|
||||
{
|
||||
Elem = Array.empty
|
||||
Nodes = Array.empty
|
||||
BBox = BBox.empty
|
||||
}
|
||||
static member empty = { Elem = Array.empty; Nodes = Array.empty; BBox = BBox.empty }
|
||||
|
||||
type ElemsAroundNode = Map<NodeIdx, ElemIdx []>
|
||||
type NodesAroundNode = Map<NodeIdx, NodeIdx []>
|
||||
type ElemsAroundNode = Map<NodeIdx, ElemIdx array>
|
||||
type NodesAroundNode = Map<NodeIdx, NodeIdx array>
|
||||
type ElemsAroundElem = Map<ElemIdx, ElemIdx array>
|
||||
|
||||
type NeighborIndex =
|
||||
{
|
||||
ElemsAroundNode: ElemsAroundNode
|
||||
NodesAroundNode: NodesAroundNode
|
||||
}
|
||||
static member empty = { ElemsAroundNode = Map.empty; NodesAroundNode = Map.empty }
|
||||
|
||||
type private Ean = Map<NodeIdx, ElemIdx list>
|
||||
type NeighborIndex = {
|
||||
ElemsAroundNode: ElemsAroundNode
|
||||
NodesAroundNode: NodesAroundNode
|
||||
ElemsAroundElem: ElemsAroundElem
|
||||
} with
|
||||
static member empty = { ElemsAroundNode = Map.empty; NodesAroundNode = Map.empty; ElemsAroundElem = Map.empty }
|
||||
|
||||
// NOTE(SimenLK): The amount of items to be stored in the trees leafs
|
||||
// let treeLeafSize = LeafNodeSize 64
|
||||
|
||||
let private createTree (points: Leaf<int> []) =
|
||||
let tree = KdTree<float, int>(2, KdTree.Math.DoubleMath())
|
||||
points
|
||||
|> Array.iter (fun a -> tree.Add([| fst a.Pos; snd a.Pos |], a.Data) |> ignore)
|
||||
let private createTree (points: Leaf<int> array) =
|
||||
let tree = KdTree<float, int> (2, KdTree.Math.DoubleMath ())
|
||||
|
||||
do points |> Array.iter (fun a -> tree.Add ([| fst a.Pos; snd a.Pos |], a.Data) |> ignore)
|
||||
if points.Length > 0 then
|
||||
tree.Balance()
|
||||
do tree.Balance ()
|
||||
else
|
||||
Log.Warning $"Empty kd-tree"
|
||||
do Log.Warning $"Empty kd-tree"
|
||||
|
||||
tree
|
||||
|
||||
type private Ean = Map<NodeIdx, ElemIdx array>
|
||||
|
||||
let private makeElemsSurroundingNodeMap (elem: Elem array) : ElemsAroundNode =
|
||||
let addElIdx k v (nodes: Ean) =
|
||||
Map.tryFind k nodes
|
||||
|> Option.defaultWith (fun () -> [])
|
||||
|> fun nds -> Map.add k (v :: nds) nodes
|
||||
elem
|
||||
|> Array.fold
|
||||
(fun (n, acc) (a, b, c) ->
|
||||
let acc' =
|
||||
acc
|
||||
|> addElIdx a n
|
||||
|> addElIdx b n
|
||||
|> addElIdx c n
|
||||
n + 1, acc')
|
||||
(0, Map.empty)
|
||||
let addElIdx k v (nodes: Ean) : Ean =
|
||||
let nds =
|
||||
Map.tryFind k nodes
|
||||
|> Option.defaultValue [||]
|
||||
nodes |> Map.add k (Array.append [|v|] nds)
|
||||
let folder (n, acc) (a, b, c) =
|
||||
let acc' = acc |> addElIdx a n |> addElIdx b n |> addElIdx c n
|
||||
n + 1, acc'
|
||||
|
||||
((0, Map.empty), elem)
|
||||
||> Array.fold folder
|
||||
|> snd
|
||||
|> Map.mapValues toArray
|
||||
|
||||
let private makeElemsSurroundingNodeMap' (elem: Elem array) : ElemsAroundNode =
|
||||
let addElemIdx k v nodes =
|
||||
@@ -108,12 +100,9 @@ let private makeElemsSurroundingNodeMap' (elem: Elem array) : ElemsAroundNode =
|
||||
elem
|
||||
|> Array.fold
|
||||
(fun (n, acc) (a, b, c) ->
|
||||
let acc' =
|
||||
acc
|
||||
|> addElemIdx a n
|
||||
|> addElemIdx b n
|
||||
|> addElemIdx c n
|
||||
n + 1, acc')
|
||||
let acc' = acc |> addElemIdx a n |> addElemIdx b n |> addElemIdx c n
|
||||
n + 1, acc'
|
||||
)
|
||||
(0, Map.empty)
|
||||
|> snd
|
||||
|> Map.mapValues toArray
|
||||
@@ -124,28 +113,45 @@ let private makeNodesSurroudingNodeMap (n2e: ElemsAroundNode) (elem: Elem array)
|
||||
n
|
||||
|> Array.collect (fun x ->
|
||||
let n1, n2, n3 = elem[x]
|
||||
[| n1; n2; n3 |])
|
||||
|> Array.distinct)
|
||||
[| n1; n2; n3 |]
|
||||
)
|
||||
|> Array.distinct
|
||||
)
|
||||
|
||||
let getSurrounding (idx: Map<int, int []>) (a, b, c) =
|
||||
[| idx[a]; idx[b]; idx[c] |]
|
||||
|> Array.concat
|
||||
|> Array.distinct
|
||||
let private makeElemsSurroundingElemMap (ean: ElemsAroundNode) (elem: Elem array) : ElemsAroundElem =
|
||||
elem
|
||||
|> Array.mapi (fun elemIdx (n1, n2, n3) ->
|
||||
// For each element, find all elements that share any of its nodes
|
||||
let surroundingElems =
|
||||
[| ean[n1]; ean[n2]; ean[n3] |]
|
||||
|> Array.concat
|
||||
|> Array.distinct
|
||||
|> Array.filter (fun x -> x <> elemIdx) // Remove self
|
||||
elemIdx, surroundingElems
|
||||
)
|
||||
|> Map.ofArray
|
||||
|
||||
let getSurrounding (idx: Map<int, int[]>) (a, b, c) =
|
||||
[| idx[a]; idx[b]; idx[c] |] |> Array.concat |> Array.distinct
|
||||
|
||||
let makeNeighborIndex (grid: IGrid) =
|
||||
let elem = grid.getCells ()
|
||||
let ean = makeElemsSurroundingNodeMap elem
|
||||
|
||||
{
|
||||
ElemsAroundNode = ean
|
||||
NodesAroundNode = makeNodesSurroudingNodeMap ean elem
|
||||
ElemsAroundElem = makeElemsSurroundingElemMap ean elem
|
||||
}
|
||||
|
||||
let getElemsSurroundingNode (idx: NeighborIndex) n = idx.ElemsAroundNode[n]
|
||||
|
||||
let getNodesSurroundingNode (idx: NeighborIndex) n = idx.NodesAroundNode[n]
|
||||
|
||||
let getNodesSurroundingElem (idx: NeighborIndex) (grid: Grid) e =
|
||||
getSurrounding idx.NodesAroundNode grid.Elem[e]
|
||||
let getNodesSurroundingElem (idx: NeighborIndex) e = idx.ElemsAroundElem[e]
|
||||
|
||||
// let getNodesSurroundingElem (idx: NeighborIndex) (grid: Grid) e =
|
||||
// getSurrounding idx.NodesAroundNode grid.Elem[e]
|
||||
|
||||
let getElemsSurroundingElem (idx: NeighborIndex) (grid: Grid) e =
|
||||
getSurrounding idx.ElemsAroundNode grid.Elem[e]
|
||||
@@ -182,61 +188,68 @@ let bboxToLngLat (coordsys: CoordinateSystem) b =
|
||||
let projectBBox proj b =
|
||||
let x0, y0 = proj (b.minX, b.minY)
|
||||
let x1, y1 = proj (b.maxX, b.maxY)
|
||||
{ minX = x0; maxX = x1; minY = y0; maxY = y1; center = proj b.center }
|
||||
{
|
||||
minX = x0
|
||||
maxX = x1
|
||||
minY = y0
|
||||
maxY = y1
|
||||
center = proj b.center
|
||||
}
|
||||
|
||||
let projectGrid proj (grid: Grid) : Grid =
|
||||
{ grid with
|
||||
let projectGrid proj (grid: Grid) : Grid = {
|
||||
grid with
|
||||
Nodes = grid.Nodes |> Array.Parallel.map proj
|
||||
BBox = projectBBox proj grid.BBox
|
||||
}
|
||||
}
|
||||
|
||||
let rescaleGrid (factor: float) (grid: Grid) : Grid =
|
||||
let nodes' = grid.Nodes |> Array.Parallel.map (fun (x, y) -> factor * x, factor * y)
|
||||
let bbox' = calcBBox nodes'
|
||||
{ grid with
|
||||
Nodes = nodes'
|
||||
BBox = bbox'
|
||||
}
|
||||
{ grid with Nodes = nodes'; BBox = bbox' }
|
||||
|
||||
let translateGrid (x0, y0) grid =
|
||||
let nodes' = grid.Nodes |> Array.Parallel.map (fun (x, y) -> x + x0, y + y0)
|
||||
let bbox' = calcBBox nodes'
|
||||
{ grid with
|
||||
Nodes = nodes'
|
||||
BBox = bbox'
|
||||
}
|
||||
{ grid with Nodes = nodes'; BBox = bbox' }
|
||||
|
||||
let toWebMercator (coordsys: CoordinateSystem) (grid: Grid) =
|
||||
let toWebMercator = makeTransform coordsys CoordSys.EPSG3857
|
||||
let s = System.Diagnostics.Stopwatch.StartNew()
|
||||
let s = System.Diagnostics.Stopwatch.StartNew ()
|
||||
let g = grid |> projectGrid toWebMercator.project
|
||||
s.Stop()
|
||||
s.Stop ()
|
||||
Log.Debug $"Reprojected grid: {s.ElapsedMilliseconds} ms"
|
||||
g
|
||||
|
||||
let toLonLat (coordsys: CoordinateSystem) (grid: Grid) =
|
||||
let toLonLat = makeTransform coordsys CoordSys.WGS84
|
||||
let s = System.Diagnostics.Stopwatch.StartNew ()
|
||||
let g = grid |> projectGrid toLonLat.project
|
||||
s.Stop ()
|
||||
Log.Debug $"Reprojected grid: {s.ElapsedMilliseconds} ms"
|
||||
g
|
||||
|
||||
let private chomp (l: string) = l.Split ' ' |> Array.filter ((<>) "")
|
||||
|
||||
// TODO: pattern match and compare sizes for more flex
|
||||
let private readGrdHeader (h: string []) =
|
||||
let private readGrdHeader (h: string[]) =
|
||||
let parse x = (chomp x)[3] |> int
|
||||
try
|
||||
let nodes = parse h[0]
|
||||
let nele = parse h[1]
|
||||
Some(nodes, nele)
|
||||
with
|
||||
| _ -> None
|
||||
Some (nodes, nele)
|
||||
with _ ->
|
||||
None
|
||||
|
||||
let private readObcHeader (h: string) =
|
||||
try
|
||||
(chomp h)[4] |> int |> Some
|
||||
with
|
||||
| _ -> None
|
||||
with _ ->
|
||||
None
|
||||
|
||||
let private reader (parser: string [] -> 'a) (f: string array) =
|
||||
let private reader (parser: string[] -> 'a) (f: string array) =
|
||||
try
|
||||
f |> Array.map (chomp >> parser) |> Some
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error e.Message
|
||||
None
|
||||
|
||||
@@ -274,13 +287,13 @@ let readGrdFile (filename: string) =
|
||||
let elem = readElem els
|
||||
let nodes = readNodes nds
|
||||
let toGrid e n = { Elem = e; Nodes = n; BBox = calcBBox n }
|
||||
toGrid <!> elem <*> nodes)
|
||||
toGrid <!> elem <*> nodes
|
||||
)
|
||||
|
||||
let readObcFile (filename: string) =
|
||||
let f = System.IO.File.ReadAllLines filename
|
||||
let hdr, rest = Array.splitAt 1 f
|
||||
readObcHeader hdr[0]
|
||||
|> Option.bind (fun _ -> readObc rest)
|
||||
readObcHeader hdr[0] |> Option.bind (fun _ -> readObc rest)
|
||||
|
||||
module Boundary =
|
||||
let normalizeElement (a, b, c) =
|
||||
@@ -294,11 +307,8 @@ module Boundary =
|
||||
match Map.tryFind edge a with
|
||||
| Some v -> Map.add edge (n :: v) a
|
||||
| None -> Map.add edge [ n ] a
|
||||
let appendEdges a (n, x: Edge []) =
|
||||
a
|
||||
|> appendEdge (n, x[0])
|
||||
|> appendEdge (n, x[1])
|
||||
|> appendEdge (n, x[2])
|
||||
let appendEdges a (n, x: Edge[]) =
|
||||
a |> appendEdge (n, x[0]) |> appendEdge (n, x[1]) |> appendEdge (n, x[2])
|
||||
grid.Elem
|
||||
|> Array.mapi normElIdx
|
||||
|> Array.fold appendEdges Map.empty
|
||||
@@ -316,8 +326,7 @@ module Boundary =
|
||||
|> Map.mapValues (fun x -> List.head x, List.last x)
|
||||
|
||||
let makeBoundaryByElementMap (edgeMap: Map<Edge, ElemIdx>) =
|
||||
edgeMap
|
||||
|> Map.fold (fun a k v -> Map.add v k a) Map.empty
|
||||
edgeMap |> Map.fold (fun a k v -> Map.add v k a) Map.empty
|
||||
|
||||
let getBoundaryNodesArray (edgeMap: Map<Edge, ElemIdx>) =
|
||||
edgeMap
|
||||
@@ -337,8 +346,7 @@ module Util =
|
||||
(x0 + x1 + x2) / 3f, (y0 + y1 + y2) / 3f
|
||||
|
||||
static member calcArea((x0, y0), (x1, y1), (x2, y2)) =
|
||||
x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)
|
||||
|> (*) 0.5
|
||||
x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1) |> (*) 0.5
|
||||
|
||||
// static member calcArea((x0, y0), (x1, y1), (x2, y2)) =
|
||||
// x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)
|
||||
@@ -356,20 +364,20 @@ module Util =
|
||||
let Sy = det Tx T2 E |> (*) 0.5
|
||||
let a = det Tx Ty E
|
||||
let b = det Tx Ty T2
|
||||
if abs a < 1.0e-12 then failwith "co-linear vertices"
|
||||
if abs a < 1.0e-12 then
|
||||
failwith "co-linear vertices"
|
||||
let S2 = (Sx, Sy) |> square
|
||||
let r = (b / a + S2 / (a * a)) |> sqrt
|
||||
Sx / a, Sy / a, r
|
||||
|
||||
static member propToNodal (nIdx: NeighborIndex) (s: float []) =
|
||||
static member propToNodal (nIdx: NeighborIndex) (s: float[]) =
|
||||
[| 0 .. nIdx.NodesAroundNode.Count - 1 |] // total number of nodes
|
||||
|> Array.Parallel.map (fun i ->
|
||||
let ns = nIdx.ElemsAroundNode[i]
|
||||
ns
|
||||
|> Array.fold (fun a n -> s[n] + a) 0.
|
||||
|> (*) (1. / float ns.Length))
|
||||
ns |> Array.fold (fun a n -> s[n] + a) 0. |> (*) (1. / float ns.Length)
|
||||
)
|
||||
|
||||
static member speedToNodal (nIdx: NeighborIndex) (s: (float * float) []) =
|
||||
static member speedToNodal (nIdx: NeighborIndex) (s: (float * float)[]) =
|
||||
[| 0 .. nIdx.NodesAroundNode.Count - 1 |] // total number of nodes
|
||||
|> Array.Parallel.map (fun i ->
|
||||
let ns = nIdx.ElemsAroundNode[i]
|
||||
@@ -377,11 +385,13 @@ module Util =
|
||||
|> Array.fold
|
||||
(fun a n ->
|
||||
let u, v = s[n]
|
||||
sqrt (u * u + v * v) + a)
|
||||
sqrt (u * u + v * v) + a
|
||||
)
|
||||
0.
|
||||
|> (*) (1. / float ns.Length))
|
||||
|> (*) (1. / float ns.Length)
|
||||
)
|
||||
|
||||
static member velocityToNodal (nIdx: NeighborIndex) (s: (float * float) []) =
|
||||
static member velocityToNodal (nIdx: NeighborIndex) (s: (float * float)[]) =
|
||||
[| 0 .. nIdx.NodesAroundNode.Count - 1 |] // total number of nodes
|
||||
|> Array.Parallel.map (fun i ->
|
||||
let ns = nIdx.ElemsAroundNode[i]
|
||||
@@ -390,9 +400,11 @@ module Util =
|
||||
|> Array.fold
|
||||
(fun (au, av) n ->
|
||||
let u, v = s[n]
|
||||
u + au, v + av)
|
||||
u + au, v + av
|
||||
)
|
||||
(0., 0.)
|
||||
|> fun (u, v) -> u / n, v / n)
|
||||
|> fun (u, v) -> u / n, v / n
|
||||
)
|
||||
|
||||
type Node =
|
||||
static member calcNodeControlArea (idx: NeighborIndex) (grid: IGrid) =
|
||||
@@ -411,8 +423,10 @@ module Util =
|
||||
let centroid = Element.calcCentroid (p0, p1, p2)
|
||||
let a1 = Element.calcArea (p0', p1', p2')
|
||||
let a2 = Element.calcArea (p1', centroid, p2')
|
||||
a1 + a2)
|
||||
|> Array.sum)
|
||||
a1 + a2
|
||||
)
|
||||
|> Array.sum
|
||||
)
|
||||
|
||||
static member calcNodeArea (idx: NeighborIndex) (grid: IGrid) =
|
||||
let nodes = grid.getVertices ()
|
||||
@@ -420,7 +434,8 @@ module Util =
|
||||
|> Array.Parallel.map (fun n ->
|
||||
getElemsSurroundingNode idx n
|
||||
|> Array.map (grid.getCellVertices >> Element.calcArea)
|
||||
|> Array.sum)
|
||||
|> Array.sum
|
||||
)
|
||||
|
||||
let calcCentroids (grid: IGrid) =
|
||||
let n = grid.getVertices ()
|
||||
@@ -429,33 +444,19 @@ module Util =
|
||||
let p0 = n[a]
|
||||
let p1 = n[b]
|
||||
let p2 = n[c]
|
||||
Element.calcCentroid (p0, p1, p2))
|
||||
Element.calcCentroid (p0, p1, p2)
|
||||
)
|
||||
|
||||
let inline isInsideTriangle (x, y, z) p =
|
||||
let sign (p1x, p1y) (p2x, p2y) (p3x, p3y) =
|
||||
(p1x - p3x) * (p2y - p3y)
|
||||
- (p2x - p3x) * (p1y - p3y)
|
||||
(p1x - p3x) * (p2y - p3y) - (p2x - p3x) * (p1y - p3y)
|
||||
|
||||
let d1 = sign p x y
|
||||
let d2 = sign p y z
|
||||
let d3 = sign p z x
|
||||
|
||||
let neg = (d1 <= 0.) || (d2 <= 0.) || (d3 <= 0.)
|
||||
let pos = (d1 >= 0.) || (d2 >= 0.) || (d3 >= 0.)
|
||||
|
||||
(neg && pos) |> not
|
||||
|
||||
let inline isInsideTriangle_dbl (x, y, z) p =
|
||||
let sign (p1x, p1y) (p2x, p2y) (p3x, p3y) =
|
||||
(p1x - p3x) * (p2y - p3y)
|
||||
- (p2x - p3x) * (p1y - p3y)
|
||||
|
||||
let d1 = sign p x y
|
||||
let d2 = sign p y z
|
||||
let d3 = sign p z x
|
||||
|
||||
let neg = (d1 <= 0.0) || (d2 <= 0.0) || (d3 <= 0.0)
|
||||
let pos = (d1 >= 0.0) || (d2 >= 0.0) || (d3 >= 0.0)
|
||||
let neg = (d1 < 0.) || (d2 < 0.) || (d3 < 0.)
|
||||
let pos = (d1 > 0.) || (d2 > 0.) || (d3 > 0.)
|
||||
|
||||
(neg && pos) |> not
|
||||
|
||||
@@ -464,7 +465,8 @@ module Util =
|
||||
grid.getVertices ()
|
||||
|> Array.mapi (fun i v ->
|
||||
let x, y = v
|
||||
{ Pos = x, y; Data = i })
|
||||
{ Pos = x, y; Data = i }
|
||||
)
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createTree
|
||||
|
||||
@@ -472,12 +474,10 @@ module Util =
|
||||
let buildNearestElementTree (grid: IGrid) =
|
||||
grid.getCells ()
|
||||
|> Array.mapi (fun i _ ->
|
||||
let pos =
|
||||
i
|
||||
|> grid.getCellVertices
|
||||
|> Element.calcCentroid
|
||||
// |> fun (x, y) -> { X = x; Y = y }
|
||||
{ Pos = pos; Data = i })
|
||||
let pos = i |> grid.getCellVertices |> Element.calcCentroid
|
||||
// |> fun (x, y) -> { X = x; Y = y }
|
||||
{ Pos = pos; Data = i }
|
||||
)
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createTree
|
||||
|
||||
@@ -493,14 +493,15 @@ module Util =
|
||||
// else None)
|
||||
|
||||
let tryFindElement (grid: IGrid) (tree: KdTree<float, int>) ((p0, p1): float * float) =
|
||||
tree.GetNearestNeighbours([| p0; p1 |], 1)
|
||||
tree.GetNearestNeighbours ([| p0; p1 |], 1)
|
||||
|> Array.tryHead
|
||||
|> Option.bind (fun leaf ->
|
||||
let vx = grid.getCellVertices leaf.Value
|
||||
if isInsideTriangle vx (p0, p1) then
|
||||
Some leaf.Value
|
||||
else
|
||||
None)
|
||||
None
|
||||
)
|
||||
|
||||
// type private IdxTree = Tree<Leaf<single, ElemIdx> array, Node<single>>
|
||||
// type private NodeIdxTree = Tree<Leaf<single, NodeIdx> array, Node<single>>
|
||||
@@ -509,23 +510,21 @@ type private NodeIdxTree = KdTree<float, int>
|
||||
|
||||
[<MessagePackObject>]
|
||||
type BinGrid = {
|
||||
[<Key(0)>] hash : byte[]
|
||||
[<Key(1)>] vertices : (float * float)[]
|
||||
[<Key(2)>] cells : (int * int * int)[]
|
||||
[<Key(0)>]
|
||||
hash: byte[]
|
||||
[<Key(1)>]
|
||||
vertices: (float * float)[]
|
||||
[<Key(2)>]
|
||||
cells: (int * int * int)[]
|
||||
} with
|
||||
member this.toGrid (): Grid =
|
||||
{
|
||||
Nodes = this.vertices
|
||||
Elem = this.cells
|
||||
BBox = calcBBox this.vertices
|
||||
}
|
||||
member this.toGrid() : Grid = { Nodes = this.vertices; Elem = this.cells; BBox = calcBBox this.vertices }
|
||||
|
||||
type ExtendedGrid(grid: IGrid) =
|
||||
let mutable nodeTree: NodeIdxTree option = None
|
||||
let mutable elementTree: IdxTree option = None
|
||||
let mutable neighborIndex: NeighborIndex option = None
|
||||
let mutable centroids: Vertex [] option = None
|
||||
let mutable gridSha1: byte[] = [||]
|
||||
let mutable centroids: Vertex[] option = None
|
||||
let mutable gridHash: byte[] = [||]
|
||||
|
||||
let getNeighborIdx () =
|
||||
match neighborIndex with
|
||||
@@ -548,12 +547,11 @@ type ExtendedGrid(grid: IGrid) =
|
||||
|
||||
member this.Grid = grid
|
||||
|
||||
member this.ToGrid() =
|
||||
{
|
||||
Nodes = this.Grid.getVertices ()
|
||||
Elem = this.Grid.getCells ()
|
||||
BBox = this.Grid.getBoundingBox ()
|
||||
}
|
||||
member this.ToGrid() = {
|
||||
Nodes = this.Grid.getVertices ()
|
||||
Elem = this.Grid.getCells ()
|
||||
BBox = this.Grid.getBoundingBox ()
|
||||
}
|
||||
|
||||
|
||||
member this.initNeighborIndex(?cache: string) =
|
||||
@@ -573,7 +571,7 @@ type ExtendedGrid(grid: IGrid) =
|
||||
|
||||
member this.nearestNode(p0: float, p1: float) =
|
||||
let nearest (tree: KdTree<_, _>) =
|
||||
tree.GetNearestNeighbours([| p0; p1 |], 1)
|
||||
tree.GetNearestNeighbours ([| p0; p1 |], 1)
|
||||
|> Array.tryHead
|
||||
|> Option.map (fun l -> l.Value)
|
||||
match nodeTree with
|
||||
@@ -586,32 +584,38 @@ type ExtendedGrid(grid: IGrid) =
|
||||
this.nearestNode p
|
||||
|> Option.bind (fun n ->
|
||||
this.getElemsSurroundingNode n
|
||||
|> Array.fold (fun (a: int option) e ->
|
||||
if a.IsNone then
|
||||
let vx = this.Grid.getCellVertices e
|
||||
if Util.isInsideTriangle vx p then Some n else None
|
||||
else a) None
|
||||
)
|
||||
|> Array.fold
|
||||
(fun (a: int option) e ->
|
||||
if a.IsNone then
|
||||
let vx = this.Grid.getCellVertices e
|
||||
if Util.isInsideTriangle vx p then Some n else None
|
||||
else
|
||||
a
|
||||
)
|
||||
None
|
||||
)
|
||||
|
||||
member private this.tryFindElementTwice (grid: IGrid) (tree: IdxTree) ((p0, p1): float * float as p) =
|
||||
Util.tryFindElement grid tree p
|
||||
|> Option.orElse (
|
||||
tree.GetNearestNeighbours([| p0; p1 |], 1)
|
||||
tree.GetNearestNeighbours ([| p0; p1 |], 1)
|
||||
|> Array.tryHead
|
||||
|> Option.bind (fun leaf ->
|
||||
this.getElemsSurroundingElem leaf.Value
|
||||
|> Array.tryFind (fun eIdx ->
|
||||
let vx = this.Grid.getCellVertices eIdx
|
||||
Util.isInsideTriangle vx p))
|
||||
Util.isInsideTriangle vx p
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
member this.tryGetElement p =
|
||||
elementTree
|
||||
|> Option.bind (fun tree ->
|
||||
this.tryFindElementTwice grid tree p)
|
||||
|> Option.bind (fun tree -> this.tryFindElementTwice grid tree p)
|
||||
|> Option.orElseWith (fun () ->
|
||||
this.initElementTree ()
|
||||
this.tryFindElementTwice grid elementTree.Value p)
|
||||
this.tryFindElementTwice grid elementTree.Value p
|
||||
)
|
||||
|
||||
member this.tryGetElementSloppy(p0, p1 as p) =
|
||||
match elementTree with
|
||||
@@ -621,22 +625,24 @@ type ExtendedGrid(grid: IGrid) =
|
||||
// this.initNodeTree ()
|
||||
Util.tryFindElement grid elementTree.Value p
|
||||
|
||||
member this.getSha1(?grid: BinGrid) =
|
||||
if grid.IsSome && grid.Value.hash.Length > 0 then
|
||||
gridSha1 <- grid.Value.hash
|
||||
elif gridSha1.Length = 0 then
|
||||
let bg : BinGrid = {
|
||||
member this.initHash(hash: byte[]) =
|
||||
if gridHash.Length = 0 && hash.Length > 0 then
|
||||
gridHash <- hash
|
||||
|
||||
member this.getHash() =
|
||||
if gridHash.Length = 0 then
|
||||
let bg: BinGrid = {
|
||||
hash = [||]
|
||||
vertices = (this :> IGrid).getVertices ()
|
||||
cells = (this :> IGrid).getCells ()
|
||||
}
|
||||
let bytes = MessagePackSerializer.Serialize(bg)
|
||||
let sha1 = System.Security.Cryptography.SHA1.Create()
|
||||
gridSha1 <- sha1.ComputeHash bytes
|
||||
gridSha1
|
||||
let bytes = MessagePackSerializer.Serialize (bg)
|
||||
let sha1 = System.Security.Cryptography.SHA1.Create ()
|
||||
gridHash <- sha1.ComputeHash bytes
|
||||
gridHash
|
||||
|
||||
member this.getSha1String() =
|
||||
this.getSha1() |> Convert.ToHexStringLower
|
||||
member this.getHashString() =
|
||||
this.getHash () |> Convert.ToHexStringLower
|
||||
|
||||
member this.getCentroids() =
|
||||
match centroids with
|
||||
@@ -651,12 +657,10 @@ type ExtendedGrid(grid: IGrid) =
|
||||
Util.Element.calcCircumscribedCircle triangle
|
||||
|
||||
member this.getElemsSurroundingNode n =
|
||||
getNeighborIdx ()
|
||||
|> fun idx -> idx.ElemsAroundNode[n]
|
||||
getNeighborIdx () |> fun idx -> idx.ElemsAroundNode[n]
|
||||
|
||||
member this.getNodesSurroundingNode n =
|
||||
getNeighborIdx ()
|
||||
|> fun idx -> idx.NodesAroundNode[n]
|
||||
getNeighborIdx () |> fun idx -> idx.NodesAroundNode[n]
|
||||
|
||||
member this.getNodesSurroundingElem e =
|
||||
let idx = getNeighborIdx ()
|
||||
@@ -669,35 +673,34 @@ type ExtendedGrid(grid: IGrid) =
|
||||
getSurrounding idx.ElemsAroundNode elem
|
||||
|
||||
member this.saveNeighborIndex(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let nix = getNeighborIdx ()
|
||||
let pickle = binarySerializer.Pickle nix
|
||||
IO.File.WriteAllBytes(fname, pickle)
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member this.loadNeighborIndex(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
if IO.File.Exists fname then
|
||||
let pickle = IO.File.ReadAllBytes fname
|
||||
neighborIndex <-
|
||||
binarySerializer.UnPickle<NeighborIndex> pickle
|
||||
|> Some
|
||||
neighborIndex <- binarySerializer.UnPickle<NeighborIndex> pickle |> Some
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
member this.saveNodeTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let tree =
|
||||
nodeTree
|
||||
|> Option.defaultWith (fun () ->
|
||||
this.initNodeTree ()
|
||||
nodeTree.Value)
|
||||
nodeTree.Value
|
||||
)
|
||||
|
||||
let pickle = binarySerializer.Pickle tree
|
||||
IO.File.WriteAllBytes(fname, pickle)
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member this.loadNodeTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
if IO.File.Exists fname then
|
||||
let pickle = IO.File.ReadAllBytes fname
|
||||
nodeTree <- binarySerializer.UnPickle<IdxTree> pickle |> Some
|
||||
@@ -706,18 +709,19 @@ type ExtendedGrid(grid: IGrid) =
|
||||
false
|
||||
|
||||
member this.saveElementTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let tree =
|
||||
elementTree
|
||||
|> Option.defaultWith (fun () ->
|
||||
this.initElementTree ()
|
||||
elementTree.Value)
|
||||
elementTree.Value
|
||||
)
|
||||
|
||||
let pickle = binarySerializer.Pickle tree
|
||||
IO.File.WriteAllBytes(fname, pickle)
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member this.loadElementTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
if IO.File.Exists fname then
|
||||
let pickle = IO.File.ReadAllBytes fname
|
||||
elementTree <- binarySerializer.UnPickle<IdxTree> pickle |> Some
|
||||
|
||||
@@ -21,9 +21,10 @@ let private calcInterpolationWeightedIdx (rn, fn) =
|
||||
let nearestIdx = Array.map (fun fzi -> findNearestZ fzi rn) fn
|
||||
nearestIdx
|
||||
|> Array.mapi (fun i j ->
|
||||
let last = Array.last rn
|
||||
if fn[i] <= rn[0] then
|
||||
(0, 0), (1.0, 0.0)
|
||||
elif fn[i] >= rn[^0] then
|
||||
elif fn[i] >= last then
|
||||
(rn.Length - 1, 0), (1.0, 0.0)
|
||||
elif abs (fn[i] - rn[j]) < 9.999999975e-07 then
|
||||
(j, 0), (1.0, 0.0)
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
module Oceanbox.FvcomKit.NorKyst
|
||||
|
||||
open System
|
||||
|
||||
open Thredds
|
||||
|
||||
let private getNorkystUrl (threddsUrl: string) (d: DateTime) =
|
||||
let url = threddsUrl
|
||||
let fmt (d: DateTime) =
|
||||
$"{d.Year}%02d{d.Month}%02d{d.Day}T00Z.nc"
|
||||
|
||||
$"{url}/fou-hi/new_norkyst800m/his/ocean_his.an.{fmt d}"
|
||||
|
||||
let private getArchiveUrls urlf (t: DateTime) =
|
||||
let t = t.ToUniversalTime ()
|
||||
let now = DateTime.Now.ToUniversalTime ()
|
||||
let dDay = (now.Date - t.Date).Days
|
||||
|
||||
if dDay < 0 then // no data available
|
||||
[]
|
||||
else
|
||||
@@ -21,4 +24,4 @@ let private getArchiveUrls urlf (t: DateTime) =
|
||||
let tryGetArchive (threddsUrl: string) (t: DateTime) =
|
||||
getArchiveUrls (getNorkystUrl threddsUrl) t
|
||||
|> tryOpenThredds
|
||||
|> Option.bind (fun (_, ds) -> tryGetTimeIndex ds t |> Option.map (fun idx -> (ds, idx)))
|
||||
|> Option.bind (fun (_, ds) -> tryGetTimeIndex ds t |> Option.map (fun idx -> ds, idx))
|
||||
@@ -10,12 +10,14 @@ let private getNorshelfUrl (threddsUrl: string) (kind: Kind) (mode: Mode) (date:
|
||||
let fmt (d: DateTime) =
|
||||
$"{d.Year}%02d{d.Month}%02d{d.Day}T00Z.nc"
|
||||
let url = threddsUrl + "/sea_norshelf_files"
|
||||
|
||||
$"{url}/{date.Year}/%02d{date.Month}/norshelf_{kind}_{mode}_{fmt date}"
|
||||
|
||||
let private getArchiveUrls urlf (t: DateTime) =
|
||||
let t = t.ToUniversalTime ()
|
||||
let now = DateTime.Now.ToUniversalTime ()
|
||||
let dDay = (now.Date - t.Date).Days
|
||||
|
||||
if dDay < -3 then // no data available
|
||||
[]
|
||||
elif dDay <= 0 then // forecast, count down from latest
|
||||
@@ -27,6 +29,7 @@ let private getArchiveUrls urlf (t: DateTime) =
|
||||
|
||||
let tryGetArchive threddsUrl avg (t: DateTime) =
|
||||
let kind = if avg then Avg else Qck
|
||||
|
||||
getArchiveUrls (getNorshelfUrl threddsUrl kind) t
|
||||
|> tryOpenThredds
|
||||
|> Option.bind (fun (fname, ds) -> tryGetTimeIndex ds t |> Option.map (fun idx -> (fname, ds, idx)))
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>Oceanbox.FvcomKit</PackageId>
|
||||
<Company>Oceanbox AS</Company>
|
||||
<Authors/>
|
||||
<Company/>
|
||||
<Version>5.9.1</Version>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<PackageId>Oceanbox.FvcomKit</PackageId>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
<Version>6.0.0</Version>
|
||||
<RestorePackagesWithLockFile>false</RestorePackagesWithLockFile>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Types.fs"/>
|
||||
@@ -32,11 +33,14 @@
|
||||
<PackageReference Include="MathNet.Numerics.FSharp" Version="5.0.0"/>
|
||||
<PackageReference Include="MessagePack" Version="3.1.3"/>
|
||||
<PackageReference Include="ProjNet.FSharp" Version="5.2.0"/>
|
||||
<PackageReference Include="SDSlite.Oceanbox" Version="2.7.3"/>
|
||||
<PackageReference Include="Oceanbox.SDSLite" Version="2.8.0"/>
|
||||
<PackageReference Include="Serilog" Version="4.2.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="9.0.0"/>
|
||||
<PackageReference Include="Thoth.Json.Net" Version="12.0.0"/>
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201"/>
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.303"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageUpdate Include="ProjNet.FSharp" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' "/>
|
||||
<PackageUpdate Include="Oceanbox.SDSLite" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' "/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module Oceanbox.FvcomKit.Thredds
|
||||
|
||||
open System
|
||||
|
||||
open Microsoft.Research.Science.Data
|
||||
open Microsoft.Research.Science.Data.NetCDF4
|
||||
open Serilog
|
||||
@@ -21,20 +22,20 @@ type Kind =
|
||||
| Avg -> "avg"
|
||||
| Qck -> "qck"
|
||||
|
||||
let dateRange (start: DateTime) days =
|
||||
let dateRange (start: DateTime) days : DateTime list =
|
||||
if days < 0 then
|
||||
List.unfold (fun d -> if d < days then None else Some (start.AddDays d, d - 1)) 0
|
||||
else
|
||||
List.unfold (fun d -> if d > days then None else Some (start.AddDays d, d + 1)) 0
|
||||
|
||||
let tryOpenArchive url =
|
||||
let tryOpenArchive url : DataSet option =
|
||||
let uri = NetCDFUri ()
|
||||
uri.Url <- url
|
||||
do uri.Url <- url
|
||||
try
|
||||
let ds = NetCDFDataSet.Open uri
|
||||
Some ds
|
||||
with e ->
|
||||
Log.Debug e.Message
|
||||
do Log.Debug e.Message
|
||||
None
|
||||
|
||||
let rec tryOpenThredds =
|
||||
@@ -42,18 +43,22 @@ let rec tryOpenThredds =
|
||||
| [] -> None
|
||||
| x :: xs ->
|
||||
match tryOpenArchive x with
|
||||
| None ->
|
||||
tryOpenThredds xs
|
||||
| Some ds ->
|
||||
Log.Debug $"thredds: {x}"
|
||||
do Log.Debug $"thredds: {x}"
|
||||
Some (x, ds)
|
||||
| None -> tryOpenThredds xs
|
||||
|
||||
let tryGetTimeIndex (ds: DataSet) (t: DateTime) =
|
||||
let ot = ds["ocean_time"].GetData () :?> double[]
|
||||
let t0 = DateTimeOffset.FromUnixTimeSeconds (ot[0] |> int64)
|
||||
let t1 = DateTimeOffset.FromUnixTimeSeconds (ot[^0] |> int64)
|
||||
Log.Debug $"t={t} t0={t0} tn={t1}"
|
||||
let first = Array.head ot
|
||||
let last = Array.last ot
|
||||
let t0 = DateTimeOffset.FromUnixTimeSeconds (first |> int64)
|
||||
let t1 = DateTimeOffset.FromUnixTimeSeconds (last |> int64)
|
||||
do Log.Debug $"t={t} t0={t0} tn={t1}"
|
||||
|
||||
if t < t0.DateTime || t > t1.DateTime then
|
||||
Log.Error "time is out of bounds"
|
||||
do Log.Error "time is out of bounds"
|
||||
None
|
||||
else
|
||||
let dt = t - t0.DateTime
|
||||
|
||||
@@ -4,6 +4,7 @@ open System
|
||||
|
||||
type Vertex = float * float
|
||||
|
||||
[<Struct>]
|
||||
type BBox = {
|
||||
minX: float
|
||||
maxX: float
|
||||
|
||||
41
src/default.nix
Normal file
41
src/default.nix
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
SDSLite,
|
||||
projnet,
|
||||
dotnet-sdk,
|
||||
dotnet-runtime,
|
||||
buildDotnetModule,
|
||||
}:
|
||||
let
|
||||
name = "Oceanbox.Fvcomkit";
|
||||
projectFile = ./Oceanbox.FvcomKit.fsproj;
|
||||
versionMatch = builtins.match ".*<Version>([^<]+)</Version>.*" (
|
||||
builtins.readFile projectFile
|
||||
);
|
||||
version = builtins.head versionMatch;
|
||||
in
|
||||
buildDotnetModule {
|
||||
name = name;
|
||||
pname = name;
|
||||
version = version;
|
||||
|
||||
src = ./.;
|
||||
|
||||
buildInputs = [
|
||||
projnet
|
||||
SDSLite
|
||||
];
|
||||
|
||||
projectFile = "Oceanbox.FvcomKit.fsproj";
|
||||
inherit
|
||||
dotnet-sdk
|
||||
dotnet-runtime
|
||||
;
|
||||
|
||||
nugetDeps = ./deps.json;
|
||||
|
||||
packNupkg = true;
|
||||
|
||||
# NOTE(mrtz): Can't package nuget without it
|
||||
# [ref](https://github.com/dotnet/fsharp/issues/12320)
|
||||
dotnetFlags = "--property:TargetsForTfmSpecificContentInPackage=";
|
||||
}
|
||||
272
src/deps.json
Normal file
272
src/deps.json
Normal file
@@ -0,0 +1,272 @@
|
||||
[
|
||||
{
|
||||
"pname": "DynamicInterop",
|
||||
"version": "0.9.1",
|
||||
"hash": "sha256-IB76dA0+K/y/2s/qYL7AfVOF0+6W2hVIBgf9YdZ1oJY="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Core",
|
||||
"version": "9.0.303",
|
||||
"hash": "sha256-AxR6wqodeU23KOTgkUfIgbavgbcSuzD4UBP+tiFydgA="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-zhVkSfqCljqr6UR0IUMOHUBlR61PvwYKq63PQ09yJPM="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-+Z7zbD8cKmhHJWg7Z8XHJ8IeJXCWr/kgRl+VbbsMFw8="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Csv.Core",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-JdOr3NDmLPohkPpZaWjKqssw0+Wr1lVDtJwTNJ/JhcY="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Csv.Core",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-oz040beVF7WMONi3n0dPQlZD5deQWnClSXKRijgnw/k="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Html.Core",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-tSstVvAT9o+0Pr6cIReJOvh0kcthOWgt1CPzgIRoYRQ="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Html.Core",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-QBbvE8WXUVjS/0mW3aohZBuyfr3M7UGw7kt1oSrlq+s="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Http",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-/PzzLT0ev4miFswct+YscFDwoaq05BSJATM4fPvxk8o="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Http",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-0YD/jSCppE1siXrUcTx0OmVdgsjMk+gn0pHp+3GS3V4="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Json.Core",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-MFe88psxmHWGQYoG8NXi4z33TlWO+dMwOV4NViaUmTM="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Json.Core",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-0Fmo0f1jC3s+Dime8j2oqLnOK+elqo1xWmktpEYrZlk="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Runtime.Utilities",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-psc/tsHLYrorjeBBBLviwwA57XMFXUP2ywZqLMzfxac="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Runtime.Utilities",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-rNo2XQMME1zrPaIezD15P0RoTu8wyhtiJyB99Qp1hcE="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.WorldBank.Core",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-QdL5ylUCvvrhvnnSPWj4MfN7B78hMbb5IRmozK7oJjM="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.WorldBank.Core",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-nUyyziwpY58UnBNpqFoe/1bgDfQIq6gOqtQIwAo7x/c="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Xml.Core",
|
||||
"version": "6.3.0",
|
||||
"hash": "sha256-67ftkfQJZ3iD62YKFh8Tu9Fuusb96KlKWxgykP1Wd9U="
|
||||
},
|
||||
{
|
||||
"pname": "FSharp.Data.Xml.Core",
|
||||
"version": "6.4.1",
|
||||
"hash": "sha256-ZiD2aiD5yUZR4CDZl6mh4ji1G3xvm4Yd9Gya/e+D32w="
|
||||
},
|
||||
{
|
||||
"pname": "FSharpPlus",
|
||||
"version": "1.5.0",
|
||||
"hash": "sha256-jQUlF3hsi3xpg+AdTnQw2L+lzbvTh5BIyLXCdVT6u6M="
|
||||
},
|
||||
{
|
||||
"pname": "FSharpPlus",
|
||||
"version": "1.7.0",
|
||||
"hash": "sha256-6hDoDOnMFXQC5Hrk6Fhd+Wj+PbPFXzL9+xLIqgILJuY="
|
||||
},
|
||||
{
|
||||
"pname": "FsPickler",
|
||||
"version": "5.3.2",
|
||||
"hash": "sha256-hjtm55aPJllzcVMPjFP4KYiEEBYtCcrUhbVOR+34agg="
|
||||
},
|
||||
{
|
||||
"pname": "KdTree",
|
||||
"version": "1.4.1",
|
||||
"hash": "sha256-R4+L26pJoliLiwMuxmJDoa3Vf16gBq417fN+iNCy7Yc="
|
||||
},
|
||||
{
|
||||
"pname": "MathNet.Numerics",
|
||||
"version": "5.0.0",
|
||||
"hash": "sha256-RHJCVM6OxquJF7n5Mbe/oNbucBbkge6ULcbAczOgmVo="
|
||||
},
|
||||
{
|
||||
"pname": "MathNet.Numerics.FSharp",
|
||||
"version": "5.0.0",
|
||||
"hash": "sha256-pPbh8JdmMjBgEu84c/qV4YJ+LLr4+c31C6t++u29qBs="
|
||||
},
|
||||
{
|
||||
"pname": "MessagePack",
|
||||
"version": "3.1.3",
|
||||
"hash": "sha256-OBn7iltr/rdE7ZKmv0MCUQSS+6OJKUYtlHdTbhEwzzE="
|
||||
},
|
||||
{
|
||||
"pname": "MessagePack.Annotations",
|
||||
"version": "3.1.3",
|
||||
"hash": "sha256-o+T3u+xaHtW1c7AeWysCmIDUfN8lRhes2LoW5iQBafs="
|
||||
},
|
||||
{
|
||||
"pname": "MessagePackAnalyzer",
|
||||
"version": "3.1.3",
|
||||
"hash": "sha256-5t4Av4CQ8HI7y9aAw+2qcOp+fsY0/3PdaFPJeCEAXQ0="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.NET.StringTools",
|
||||
"version": "17.11.4",
|
||||
"hash": "sha256-lWfzY35WQ+iKS9TpuztDTljgF9CIORhFhFEm0p1dVBE="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.NETCore.Platforms",
|
||||
"version": "1.1.0",
|
||||
"hash": "sha256-FeM40ktcObQJk4nMYShB61H/E8B7tIKfl9ObJ0IOcCM="
|
||||
},
|
||||
{
|
||||
"pname": "Microsoft.NETCore.Targets",
|
||||
"version": "1.1.0",
|
||||
"hash": "sha256-0AqQ2gMS8iNlYkrD+BxtIg7cXMnr9xZHtKAuN4bjfaQ="
|
||||
},
|
||||
{
|
||||
"pname": "ProjNET",
|
||||
"version": "2.0.0",
|
||||
"hash": "sha256-GjBnuGXmdFagIw9mX51Kpu/nn4gXta6a0cK/dxOWaZY="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.any.System.IO",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-vej7ySRhyvM3pYh/ITMdC25ivSd0WLZAaIQbYj/6HVE="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.any.System.Reflection",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-ns6f++lSA+bi1xXgmW1JkWFb2NaMD+w+YNTfMvyAiQk="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.any.System.Reflection.Primitives",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-LkPXtiDQM3BcdYkAm5uSNOiz3uF4J45qpxn5aBiqNXQ="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.any.System.Runtime",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-qwhNXBaJ1DtDkuRacgHwnZmOZ1u9q7N8j0cWOLYOELM="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.any.System.Text.Encoding",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-Q18B9q26MkWZx68exUfQT30+0PGmpFlDgaF0TnaIGCs="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.any.System.Threading.Tasks",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-agdOM0NXupfHbKAQzQT8XgbI9B8hVEh+a/2vqeHctg4="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.native.System",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-ZBZaodnjvLXATWpXXakFgcy6P+gjhshFXmglrL5xD5Y="
|
||||
},
|
||||
{
|
||||
"pname": "runtime.unix.System.Private.Uri",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-c5tXWhE/fYbJVl9rXs0uHh3pTsg44YD1dJvyOA0WoMs="
|
||||
},
|
||||
{
|
||||
"pname": "Serilog",
|
||||
"version": "4.2.0",
|
||||
"hash": "sha256-7f3EpCsEbDxXgsuhE430KVI14p7oDUuCtwRpOCqtnbs="
|
||||
},
|
||||
{
|
||||
"pname": "Serilog.Sinks.Console",
|
||||
"version": "6.0.0",
|
||||
"hash": "sha256-QH8ykDkLssJ99Fgl+ZBFBr+RQRl0wRTkeccQuuGLyro="
|
||||
},
|
||||
{
|
||||
"pname": "Serilog.Sinks.File",
|
||||
"version": "6.0.0",
|
||||
"hash": "sha256-KQmlUpG9ovRpNqKhKe6rz3XMLUjkBqjyQhEm2hV5Sow="
|
||||
},
|
||||
{
|
||||
"pname": "Serilog.Sinks.Seq",
|
||||
"version": "9.0.0",
|
||||
"hash": "sha256-NnAkRbxwQGdNXz6DDONRxorNh1nqH2TfAQtokbq5qDw="
|
||||
},
|
||||
{
|
||||
"pname": "System.IO",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-ruynQHekFP5wPrDiVyhNiRIXeZ/I9NpjK5pU+HPDiRY="
|
||||
},
|
||||
{
|
||||
"pname": "System.Memory",
|
||||
"version": "4.5.3",
|
||||
"hash": "sha256-Cvl7RbRbRu9qKzeRBWjavUkseT2jhZBUWV1SPipUWFk="
|
||||
},
|
||||
{
|
||||
"pname": "System.Numerics.Vectors",
|
||||
"version": "4.5.0",
|
||||
"hash": "sha256-qdSTIFgf2htPS+YhLGjAGiLN8igCYJnCCo6r78+Q+c8="
|
||||
},
|
||||
{
|
||||
"pname": "System.Private.Uri",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-fVfgcoP4AVN1E5wHZbKBIOPYZ/xBeSIdsNF+bdukIRM="
|
||||
},
|
||||
{
|
||||
"pname": "System.Reflection",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-NQSZRpZLvtPWDlvmMIdGxcVuyUnw92ZURo0hXsEshXY="
|
||||
},
|
||||
{
|
||||
"pname": "System.Reflection.Emit.ILGeneration",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-mKRknEHNls4gkRwrEgi39B+vSaAz/Gt3IALtS98xNnA="
|
||||
},
|
||||
{
|
||||
"pname": "System.Reflection.Emit.Lightweight",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-rKx4a9yZKcajloSZHr4CKTVJ6Vjh95ni+zszPxWjh2I="
|
||||
},
|
||||
{
|
||||
"pname": "System.Reflection.Primitives",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-5ogwWB4vlQTl3jjk1xjniG2ozbFIjZTL9ug0usZQuBM="
|
||||
},
|
||||
{
|
||||
"pname": "System.Runtime",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-51813WXpBIsuA6fUtE5XaRQjcWdQ2/lmEokJt97u0Rg="
|
||||
},
|
||||
{
|
||||
"pname": "System.Text.Encoding",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-GctHVGLZAa/rqkBNhsBGnsiWdKyv6VDubYpGkuOkBLg="
|
||||
},
|
||||
{
|
||||
"pname": "System.Threading.Tasks",
|
||||
"version": "4.3.0",
|
||||
"hash": "sha256-Z5rXfJ1EXp3G32IKZGiZ6koMjRu0n8C1NGrwpdIen4w="
|
||||
}
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
module Tests
|
||||
|
||||
open Expecto
|
||||
|
||||
let server =
|
||||
testList
|
||||
"Server"
|
||||
[
|
||||
testCase "Adding valid Todo"
|
||||
<| fun _ ->
|
||||
let expectedResult = Ok()
|
||||
Expect.equal (Ok()) expectedResult "Result should be ok"
|
||||
]
|
||||
|
||||
let all = testList "All" [ server ]
|
||||
|
||||
[<EntryPoint>]
|
||||
let main _ = runTests defaultConfig all
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Tests.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\src\Oceanbox.FvcomKit.fsproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Expecto" Version="10.2.2" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
189
xtest/Arome.fs
Normal file
189
xtest/Arome.fs
Normal file
@@ -0,0 +1,189 @@
|
||||
module Arome
|
||||
|
||||
open System
|
||||
|
||||
open Microsoft.Research.Science.Data
|
||||
|
||||
open Xunit
|
||||
open FsUnit.Xunit
|
||||
open FsUnit.CustomMatchers
|
||||
open Serilog
|
||||
open ProjNet.FSharp
|
||||
|
||||
open Oceanbox.FvcomKit
|
||||
|
||||
let logger =
|
||||
LoggerConfiguration()
|
||||
.MinimumLevel.Is(Events.LogEventLevel.Verbose)
|
||||
.WriteTo.Console()
|
||||
.CreateLogger()
|
||||
|
||||
do Log.Logger <- logger
|
||||
|
||||
[<Literal>]
|
||||
let private path = "/data/archives/Arome/meps_det_sfc_20220102T00Z.nc"
|
||||
|
||||
let trans = makeTransform CoordSys.WGS84 (CoordSys.LCCMet ())
|
||||
|
||||
// Use Netcdf to open dataset
|
||||
let private openDataset (path: string) : DataSet =
|
||||
let sw = Diagnostics.Stopwatch.StartNew()
|
||||
let uri = NetCDF4.NetCDFUri()
|
||||
do uri.FileName <- path
|
||||
do uri.OpenMode <- ResourceOpenMode.ReadOnly
|
||||
do uri.Deflate <- NetCDF4.DeflateLevel.Off
|
||||
let ds = NetCDF4.NetCDFDataSet.Open uri
|
||||
do Log.Debug $"openDataSet: {path} completed in {sw.ElapsedMilliseconds}ms"
|
||||
|
||||
ds
|
||||
|
||||
let private aromeGrid = {
|
||||
Arome.SquareGrid.empty with
|
||||
dimensions = 949, 1069
|
||||
BBox = {
|
||||
minX = -18.12241427
|
||||
maxX = 54.24126163
|
||||
minY = 49.7653854
|
||||
maxY = 75.22869642
|
||||
center = 27.12063081, 37.61434821
|
||||
}
|
||||
squareSize = 2.444065489
|
||||
}
|
||||
|
||||
[<Fact>]
|
||||
let ``Create grid``() =
|
||||
use ds = openDataset path
|
||||
let res = Arome.getGrid ds
|
||||
|
||||
// "Should be able to create square grid from /data/archives/Arome/meps_det_sfc_20220102T00Z.nc"
|
||||
res |> should be (ofCase <@ Result<Arome.SquareGrid, string>.Ok @>)
|
||||
|
||||
[<Fact>]
|
||||
let ``test grid regularity``() =
|
||||
let trans = makeTransform CoordSys.WGS84 (CoordSys.LCCMet ())
|
||||
use ds = openDataset path
|
||||
let dimensions = ds.Dimensions["x"].Length, ds.Dimensions["y"].Length
|
||||
let longs : float array2d = ds["longitude"].GetData () :?> float[,]
|
||||
let lats : float array2d = ds["latitude"].GetData () :?> float[,]
|
||||
// NOTE: The netcdf file dimensions are defined as (y, x)
|
||||
let width = Array2D.length2 longs
|
||||
let height = Array2D.length1 lats
|
||||
let points : Arome.Points array =
|
||||
let result = Array.create (width * height) Arome.Points.Zero
|
||||
for i in 0 .. height - 1 do
|
||||
for j in 0 .. width - 1 do
|
||||
let lat = lats[i, j]
|
||||
let lon = longs[i, j]
|
||||
let p = lon, lat
|
||||
// NOTE(simkir): Convert to lambert and undo all I've done... :(
|
||||
let x, y = trans.project p
|
||||
result[i * width + j] <- Arome.Points.OfTuple (single x, single y)
|
||||
result
|
||||
|
||||
let mutable acc = 0.0f
|
||||
for i in 0 .. height - 1 do
|
||||
for j in 0 .. width - 2 do
|
||||
let p0 = points[i * width + j]
|
||||
let p1 = points[i * width + j + 1]
|
||||
let dx = if p0.x < p1.x then p1.x - p0.x else p0.x - p1.x
|
||||
|
||||
acc <- acc + dx
|
||||
|
||||
let count = width * height
|
||||
let avgDiffX = acc / single count
|
||||
Log.Debug("Avg. X distance: {Avg}m", avgDiffX)
|
||||
|
||||
acc <- 0.0f
|
||||
for i in 0 .. height - 2 do
|
||||
for j in 0 .. width - 1 do
|
||||
let p0 = points[i * width + j]
|
||||
let p1 = points[(i + 1) * width + j]
|
||||
let dy = if p0.y < p1.y then p1.y - p0.y else p0.y - p1.y
|
||||
|
||||
acc <- acc + dy
|
||||
let avgDiffY = acc / single count
|
||||
Log.Debug("Avg. Y distance: {Avg}m", avgDiffY)
|
||||
|
||||
[<Fact>]
|
||||
let ``point within first rect``() =
|
||||
use ds = openDataset path
|
||||
let res = Arome.getGrid ds
|
||||
|
||||
match res with
|
||||
| Ok grid ->
|
||||
let width, _height = grid.dimensions
|
||||
let p0 = grid.points[0 * width + 0]
|
||||
let p1 = grid.points[1 * width + 1]
|
||||
let rect = Arome.Rect.OfPoints p0 p1
|
||||
// { x = -1064984.25f y = -1353489.375f }, { x = -1062474.625f y = -1350985.875f }
|
||||
let p2 = Arome.Points.OfTuple (-1063000.25f, -1353486.0f)
|
||||
let within = Arome.Rect.pointWithin rect p2
|
||||
|
||||
within |> should equal true
|
||||
| Error _ ->
|
||||
failwith "Should create grid"
|
||||
|
||||
[<Fact>]
|
||||
let ``Read uvs for index (1, 1)``() =
|
||||
use ds = openDataset path
|
||||
let res = Arome.getGrid ds
|
||||
match res with
|
||||
| Ok grid ->
|
||||
let idx =
|
||||
let lat = 50.35
|
||||
let lon = 0.304
|
||||
let p = trans.project((lon, lat))
|
||||
Arome.tryFindIndex grid p
|
||||
|
||||
match idx with
|
||||
| Some (i, j) ->
|
||||
let u, v = Arome.readUV ds 0 i j
|
||||
(u, v) |> should equal (8.530239f, 6.659096f) // "Find uv (8.530239, 6.659096) at index (1, 1)"
|
||||
| None ->
|
||||
failwith "Should find idx"
|
||||
| Error _ ->
|
||||
failwith "Should find grid"
|
||||
|
||||
[<Fact>]
|
||||
let ``Try search index (1, 1069) based on map coords``() =
|
||||
let lat = 72.800
|
||||
let lon = -17.850
|
||||
let p = trans.project((lon, lat))
|
||||
let res =
|
||||
use ds = openDataset path
|
||||
Arome.getGrid ds
|
||||
|
||||
match res with
|
||||
| Ok grid ->
|
||||
let idx = Arome.tryFindIndex grid p
|
||||
|
||||
idx |> should equal (Some (4, 1067)) // "Should find idx (1, 1069)"
|
||||
| Error _ ->
|
||||
failwith "Should find grid"
|
||||
|
||||
[<Fact>]
|
||||
let ``Read uvs for pos (60.3562, 5.2178)``() =
|
||||
let lat = 60.3562
|
||||
let lon = 5.2178
|
||||
let p = trans.project((lon, lat))
|
||||
use ds = openDataset path
|
||||
let res = Arome.getGrid ds
|
||||
match res with
|
||||
| Ok grid ->
|
||||
let idx = Arome.tryFindIndex grid p
|
||||
match idx with
|
||||
| Some (i, j) ->
|
||||
let u, v = Arome.readUV ds 0 i j
|
||||
// "Find uv (2.367153168, -0.3955917358) at pos (60.3562, 5.2178) almost in Bergen"
|
||||
(u, v) |> should equal (-0.3750343323f, 7.744056702f)
|
||||
| None ->
|
||||
failwith "Should find idx"
|
||||
| Error _ ->
|
||||
failwith "Should find grid"
|
||||
|
||||
[<Fact>]
|
||||
let ``Read uvs for t 23 x 43 y 144``() =
|
||||
use ds = openDataset path
|
||||
let u, v = Arome.readUV ds 23 43 144
|
||||
// "Find uv (2.367153168, -0.3955917358) at pos (60.3562, 5.2178) almost in Bergen"
|
||||
(u, v) |> should equal (11.77926254f, 5.764093399f)
|
||||
38
xtest/xtest.fsproj
Normal file
38
xtest/xtest.fsproj
Normal file
@@ -0,0 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>xtest</RootNamespace>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||
<!--
|
||||
This template uses native xUnit.net command line options when using 'dotnet run' and
|
||||
VSTest by default when using 'dotnet test'. For more information on how to enable support
|
||||
for Microsoft Testing Platform, please visit:
|
||||
https://xunit.net/docs/getting-started/v3/microsoft-testing-platform
|
||||
-->
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Arome.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FsUnit" Version="7.1.1" />
|
||||
<PackageReference Include="FsUnit.xUnit" Version="7.1.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
|
||||
<PackageReference Include="Oceanbox.SDSLite" Version="2.8.0" />
|
||||
<PackageReference Include="xunit.v3" Version="3.2.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\src\Oceanbox.FvcomKit.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
3
xtest/xunit.runner.json
Normal file
3
xtest/xunit.runner.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json"
|
||||
}
|
||||
Reference in New Issue
Block a user