Compare commits
303 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 | |||
|
|
76cd56e1ab | ||
| 47279b49cb | |||
| abdb949113 | |||
|
|
5464bc34f8 | ||
| 3086ef5ebf | |||
| 21e84d07cd | |||
|
|
376891e4a0 | ||
| f19a74fc9d | |||
| cef71eb90a | |||
| 222b022662 | |||
| bf7ae5889b | |||
|
|
817c02b5a6 | ||
|
|
86e1307d79 | ||
|
|
9abd9d45bc | ||
|
|
02de20d50b | ||
|
|
c8a838c1e6 | ||
|
|
17685ac2cd | ||
|
|
6662ad4ebf | ||
|
|
46209553a8 | ||
|
|
ed0ac797d3 | ||
|
|
63dc1f2cca | ||
|
|
0f5de91d39 | ||
|
|
f2730ad1e3 | ||
|
|
ef172fa883 | ||
|
|
8d7ab4164c | ||
|
|
ff283cd910 | ||
|
|
35e1f43fc0 | ||
|
|
3f61f1d1a9 | ||
|
|
ac5aad659b | ||
|
|
746f58b29e | ||
|
|
bc130658e9 | ||
|
|
aba0917557 | ||
|
|
72a49a8039 | ||
|
|
d75db35d8b | ||
|
|
94f5eb56a0 | ||
|
|
cfbf2b1d61 | ||
|
|
e09caf7a12 | ||
|
|
0f2b69609c | ||
|
|
8152537ee7 | ||
|
|
b1341581a1 | ||
|
|
d2e362df20 | ||
|
|
f38f06c936 | ||
|
|
90b50c3c83 | ||
|
|
5f5ad1b9e4 | ||
|
|
4ca7fff09e | ||
|
|
7e9e8db9cb | ||
|
|
5479c8b598 | ||
|
|
de0a4a2751 | ||
|
|
902ac080e9 | ||
|
|
22b65f878a | ||
|
|
c53c2b5b05 | ||
|
|
86d250916e | ||
|
|
4556a9fd9a | ||
|
|
b67653179f | ||
|
|
5a1ffcdf36 | ||
|
|
540a913fb4 | ||
|
|
4b889998ac | ||
|
|
01183f7469 | ||
|
|
d749f1b157 | ||
|
|
1bba6431c4 | ||
|
|
29a7c6c148 | ||
|
|
672e52cb8b | ||
|
|
f6ee353980 | ||
|
|
0d0bf9e873 | ||
|
|
eb2a981576 | ||
|
|
ff947bb364 | ||
|
|
36bd52d3f1 | ||
|
|
48ea6dd573 | ||
|
|
5511abbbfc | ||
|
|
460f8f10eb | ||
|
|
764bdedb45 | ||
|
|
82b4ceea36 | ||
|
|
434ab6d5f4 | ||
|
|
302c4f1048 | ||
|
|
e7bb5540ef | ||
|
|
bb57404523 | ||
|
|
86384bfd9f | ||
|
|
2be8397297 | ||
|
|
e9f10c8f12 | ||
|
|
6881554909 | ||
|
|
a6a8828ae9 | ||
|
|
a9d7662a2b | ||
|
|
774c840a84 | ||
|
|
41841e0d2a | ||
|
|
7b3a14e073 | ||
|
|
b1a6225f5e | ||
|
|
bb73564a00 | ||
|
|
347a730e13 | ||
|
|
7d81ac771a | ||
|
|
efeec1519e | ||
|
|
886234b165 | ||
|
|
bab002d1a6 | ||
|
|
f851e5411b | ||
|
|
af4833b555 | ||
|
|
0bf255d510 | ||
|
|
ce8b1e593b | ||
|
|
13e689d68e | ||
|
|
3305417c4b | ||
|
|
ab63c39993 | ||
|
|
1caa90c246 | ||
|
|
8c1c3e750f | ||
|
|
23fea2fd82 | ||
|
|
a2b6a3b04f | ||
|
|
116a714748 | ||
|
|
0bf18891b2 | ||
|
|
2ae5666f01 | ||
|
|
1939213ec4 | ||
|
|
7164c1793a | ||
|
|
7c977abaa3 | ||
|
|
2b361738a6 | ||
|
|
e7da5922cf | ||
|
|
8cd202a699 | ||
|
|
603785f07e | ||
|
|
e2e2585861 | ||
|
|
e2c977b843 | ||
|
|
4c04182843 | ||
|
|
c4b927553b | ||
|
|
3c9a7a701e | ||
|
|
0e28771da2 | ||
|
|
fda547eb18 | ||
|
|
cbe31b94b5 | ||
|
|
b7c488af51 | ||
|
|
68caf51645 | ||
|
|
218c4f81d7 | ||
|
|
9e925df063 | ||
|
|
d980217b3f | ||
|
|
8190554923 | ||
|
|
ba964dc7a4 | ||
|
|
2a545be683 | ||
|
|
7a8c31c79f | ||
|
|
5897cae4ad | ||
|
|
029e59dd86 | ||
|
|
4d28dd09d4 | ||
|
|
1cab11cb3e | ||
|
|
bcaca0cd2f | ||
|
|
98e52e7c42 | ||
|
|
0a8b31c1f3 | ||
|
|
49c1c25ee5 | ||
|
|
7955a76178 | ||
|
|
b6cdd4f2f2 | ||
|
|
9f8deb93de | ||
|
|
1b6c6a37bf | ||
|
|
80b2651f24 | ||
|
|
8906415812 | ||
|
|
060c7753a2 | ||
|
|
ac949c0df8 | ||
|
|
dd8659a531 | ||
|
|
aab00e9651 | ||
|
|
3ff48ceaf9 | ||
|
|
3e71d34bcb | ||
|
|
c6175f2e14 | ||
|
|
cf68ceda3b | ||
|
|
223078ad8b | ||
|
|
b4a2c27b26 | ||
|
|
e19cb18ecb | ||
|
|
dd7815e886 | ||
|
|
c857856b5e | ||
|
|
b4500ceaa6 | ||
|
|
8838018ee0 | ||
|
|
267de9b4be | ||
|
|
e3842e9d0b | ||
|
|
126180f40d | ||
|
|
5c844026b6 | ||
|
|
39c2350deb | ||
|
|
8e9328098b | ||
|
|
856fdbee40 | ||
|
|
001eede4e5 | ||
|
|
3345ce6fbd | ||
|
|
8665dc5f90 | ||
|
|
135def2573 | ||
|
|
8782ca450c | ||
|
|
ff7a0b65cd | ||
|
|
7c22c3bdc3 | ||
|
|
f59e2b627f | ||
|
|
9fa5a37709 | ||
|
|
0dc63442aa | ||
|
|
a51c60bc3a | ||
|
|
017b6f3da3 | ||
|
|
f8fce6fe87 | ||
|
|
49a7fb384a | ||
|
|
989f2c71c7 | ||
|
|
e150b3fe48 | ||
|
|
68175bbdd1 | ||
|
|
3d63732450 | ||
|
|
bccf7670b7 | ||
|
|
9382b46f38 | ||
|
|
cddc518917 | ||
|
|
8ae0793461 | ||
|
|
f1f56e1305 | ||
|
|
921bfbde0c | ||
|
|
8ac41228a1 | ||
|
|
8ba4de5bb0 | ||
|
|
7e411693d5 | ||
|
|
9f573c3506 | ||
|
|
d9b9cd2b0e | ||
|
|
9d87ea4001 | ||
|
|
e117e58bec | ||
|
|
611ecb88a7 | ||
|
|
75aa45392f | ||
|
|
4d527a1891 | ||
|
|
252141fea0 | ||
|
|
f705661392 | ||
|
|
6c5652ee68 | ||
|
|
483622f121 | ||
|
|
6d712b0928 | ||
|
|
0ae2652fcc | ||
|
|
25666f1b87 | ||
|
|
e66964d8e0 | ||
|
|
35d0f629db | ||
|
|
753e72acae | ||
|
|
0b3f603e41 | ||
|
|
af26509fa4 | ||
|
|
f5ffc641c6 | ||
|
|
a5698ff89a | ||
|
|
96f2888e58 | ||
|
|
7efc6a1d52 | ||
|
|
ede1a3d3d5 | ||
|
|
2a418c35bb | ||
|
|
ff268d461f | ||
|
|
ea29fcb601 | ||
|
|
e6ba223354 | ||
|
|
dd85f6fb21 | ||
|
|
bc9831c03f | ||
|
|
8143571a4b | ||
|
|
2713e9d4af | ||
|
|
225754bc4b | ||
|
|
13cc975ab7 | ||
|
|
1af2f322dd | ||
|
|
3f2fd296f6 | ||
|
|
7012d2b2ca | ||
|
|
ddfca6eda1 | ||
|
|
e43866d0bd | ||
|
|
7dfa5831ab | ||
|
|
1c749355fb | ||
|
|
db52e83a8f | ||
|
|
d0f7bd78ae | ||
|
|
b564dec305 | ||
|
|
db7fe87a5a | ||
|
|
b0f45fbd86 | ||
|
|
13b1e8f1a9 | ||
|
|
a1d4c69df8 | ||
|
|
b37d257674 | ||
|
|
37613cb19f | ||
|
|
5d8ea38b8f | ||
|
|
55abc1b51b | ||
|
|
cb72780e38 | ||
|
|
b569b497d0 | ||
|
|
b43466fb24 | ||
|
|
b8fdf3f2fd | ||
|
|
f869d2611b | ||
|
|
7fef736cec | ||
|
|
ecceccd297 | ||
|
|
6810092602 | ||
|
|
7ebad27419 | ||
|
|
aef93d2d4f | ||
|
|
8eabb2b3bd | ||
|
|
b8fd0e0a19 | ||
|
|
1713d25fe1 | ||
|
|
ee97e7de9d | ||
|
|
d41790a2be | ||
|
|
e26f8db139 | ||
|
|
221215f50b | ||
|
|
017dfc9eda | ||
|
|
58065024ff | ||
|
|
85746d5558 | ||
|
|
6e75e0282f | ||
|
|
26524f1136 | ||
|
|
cfaca7ed50 | ||
|
|
668da7bc3b | ||
|
|
11aa570aa5 | ||
|
|
67c4bd97db | ||
|
|
e438f7a885 | ||
|
|
f81b703d6f | ||
|
|
b183a1af05 | ||
|
|
728d0d8a4c | ||
|
|
9ee83739bf | ||
|
|
15dfd83e15 | ||
|
|
b532951e85 |
@@ -11,23 +11,23 @@ let srcPath = Path.getFullName "src"
|
||||
let testPath = Path.getFullName "test"
|
||||
let libPath = Some srcPath
|
||||
|
||||
let deployPath = Path.getFullName "deploy"
|
||||
let distPath = Path.getFullName "dist"
|
||||
let packPath = Path.getFullName "packages"
|
||||
let versionFile = Path.getFullName ".version"
|
||||
|
||||
Target.create "Clean" (fun _ -> Shell.cleanDir deployPath)
|
||||
Target.create "Clean" (fun _ -> Shell.cleanDir distPath)
|
||||
|
||||
Target.create "InstallClient" (fun _ ->
|
||||
run npm "install" "."
|
||||
run bun "install" "."
|
||||
run dotnet "tool restore" "."
|
||||
)
|
||||
|
||||
Target.create "Bundle" (fun _ ->
|
||||
run dotnet $"publish -c Release -o \"{deployPath}\"" srcPath
|
||||
run dotnet $"publish -c Release -o \"{distPath}\"" srcPath
|
||||
)
|
||||
|
||||
Target.create "BundleDebug" (fun _ ->
|
||||
run dotnet $"publish -c Debug -o \"{deployPath}\"" srcPath
|
||||
run dotnet $"publish -c Debug -o \"{distPath}\"" srcPath
|
||||
)
|
||||
|
||||
Target.create "Pack" (fun _ ->
|
||||
|
||||
@@ -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,18 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"fable": {
|
||||
"version": "3.7.0",
|
||||
"commands": [
|
||||
"fable"
|
||||
]
|
||||
},
|
||||
"fantomas-tool": {
|
||||
"version": "4.6.4",
|
||||
"commands": [
|
||||
"fantomas"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,30 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:6.0
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0
|
||||
|
||||
# Add keys and sources lists
|
||||
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash
|
||||
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" \
|
||||
| tee /etc/apt/sources.list.d/yarn.list
|
||||
# Bun version
|
||||
ARG BUN_INSTALL=/usr/local
|
||||
ARG BUN_VERSION=bun-v1.2.16
|
||||
|
||||
# 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
|
||||
|
||||
@@ -7,26 +7,30 @@ charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = false
|
||||
|
||||
[*.js]
|
||||
indent_size = 2
|
||||
max_line_length= 80
|
||||
|
||||
[*.nix]
|
||||
indent_size = 2
|
||||
max_line_length= 80
|
||||
|
||||
[*.fs]
|
||||
max_line_length=120
|
||||
# Feliz style
|
||||
fsharp_single_argument_web_mode=true
|
||||
fsharp_space_before_colon=false
|
||||
fsharp_max_if_then_else_short_width=60
|
||||
fsharp_max_infix_operator_expression=50
|
||||
fsharp_max_record_width=70
|
||||
fsharp_max_record_number_of_items=1
|
||||
fsharp_max_array_or_list_width=70
|
||||
fsharp_max_array_or_list_number_of_items=1
|
||||
fsharp_max_value_binding_width=70
|
||||
fsharp_max_function_binding_width=40
|
||||
fsharp_max_dot_get_expression_width=50
|
||||
fsharp_multiline_block_brackets_on_same_column=true
|
||||
fsharp_newline_between_type_definition_and_members=false
|
||||
fsharp_max_elmish_width=40
|
||||
fsharp_align_function_signature_to_indentation=false
|
||||
fsharp_alternative_long_member_definitions=false
|
||||
fsharp_multi_line_lambda_closing_newline=false
|
||||
fsharp_disable_elmish_syntax=false
|
||||
fsharp_keep_indent_in_branch=false
|
||||
fsharp_blank_lines_around_nested_multiline_expressions=false
|
||||
max_line_length= 120
|
||||
|
||||
fsharp_max_if_then_else_short_width = 60
|
||||
fsharp_max_infix_operator_expression = 80
|
||||
|
||||
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
|
||||
fsharp_max_array_or_list_number_of_items = 3
|
||||
|
||||
fsharp_record_multiline_formatter = number_of_items
|
||||
fsharp_max_record_number_of_items = 3
|
||||
fsharp_max_record_width = 70
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -15,3 +15,6 @@ deploy
|
||||
.ionide/
|
||||
*.db
|
||||
build.fsx.lock
|
||||
dist/
|
||||
.direnv/
|
||||
result*
|
||||
@@ -1,9 +1,11 @@
|
||||
variables:
|
||||
DEPLOY_NAME: default
|
||||
DEPLOY_NAMESPACE: default
|
||||
SDK_VERSION: 9.0
|
||||
SKIP_TESTS: "true"
|
||||
|
||||
include:
|
||||
- project: oceanbox/gitlab-ci
|
||||
ref: main
|
||||
ref: v4.1
|
||||
file: DotnetPackage.gitlab-ci.yml
|
||||
|
||||
inputs:
|
||||
project-name: oceanbox.fvcomkit
|
||||
project-dir: .
|
||||
|
||||
14
Build.fsproj
14
Build.fsproj
@@ -1,17 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include=".build/Helpers.fs" />
|
||||
<Compile Include=".build/Build.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Fake.Core.Target" Version="5.22.0" />
|
||||
<PackageReference Include="Fake.DotNet.Cli" Version="5.22.0" />
|
||||
<PackageReference Include="Fake.IO.FileSystem" Version="5.22.0" />
|
||||
<PackageReference Include="Farmer" Version="1.6.34" />
|
||||
<PackageReference Update="FSharp.Core" Version="6.0.4-beta.22181.2" />
|
||||
<PackageReference Include="Fake.Core.Target" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.DotNet.Cli" Version="6.1.3" />
|
||||
<PackageReference Include="Fake.IO.FileSystem" Version="6.1.3" />
|
||||
<PackageReference Include="Farmer" Version="1.9.11" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.201" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -1,77 +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
|
||||
Dockerfile = Dockerfile
|
||||
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
|
||||
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(NestedProjects) = preSolution
|
||||
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>
|
||||
613
RELEASE_NOTES.md
613
RELEASE_NOTES.md
@@ -1,5 +1,618 @@
|
||||
# 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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use sha from bingrid if it exists ([abdb949](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/abdb94911343c7dff214047ec8bacf740aeffe97))
|
||||
|
||||
# [5.9.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.8.0...v5.9.0) (2025-03-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ToGrid() method to extended grid ([21e84d0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/21e84d07cd4cf1593ae3e9c9f65718d221adcf1e))
|
||||
|
||||
# [5.8.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.7.0...v5.8.0) (2025-03-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* compute sha1 checksum of extended grids ([bf7ae58](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/bf7ae5889b48efb871c8c3b5ee4f07ae6ce34865))
|
||||
|
||||
# [5.7.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.6.0...v5.7.0) (2025-02-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add read omega block ([9abd9d4](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/9abd9d45bc3ce5ec2708f9e2dcbb1366190aad9c))
|
||||
|
||||
# [5.6.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.5.5...v5.6.0) (2024-11-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* update to net9.0 ([17685ac](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/17685ac2cd781a05da5064d344ab6e75597d48f9))
|
||||
|
||||
## [5.5.5](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.5.4...v5.5.5) (2024-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add velocity to nodal function ([ed0ac79](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/ed0ac797d378c7acc0dba29cc5d95f10d1e0fe3a))
|
||||
|
||||
## [5.5.4](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.5.3...v5.5.4) (2024-05-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Norshelf filenames changed due to changes in Thredds ([0f5de91](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/0f5de91d39e7fae82b17bfc5fd014f731c7d2b9d))
|
||||
|
||||
## [5.5.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.5.2...v5.5.3) (2024-02-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bug in isInsideTriangle ([8d7ab41](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8d7ab4164c2817906c539b1c632c9ea820de7e5d))
|
||||
|
||||
## [5.5.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.5.1...v5.5.2) (2024-01-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix ci/cd deploy name ([35e1f43](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/35e1f43fc00dd31c2ec442a3e81d6b715011e66e))
|
||||
* update ci/cd setup to v2 ([3f61f1d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/3f61f1d1a9c98dfc6be98540cfbc65e90b50cc36))
|
||||
|
||||
## [5.5.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.5.0...v5.5.1) (2024-01-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bump to sdk_8 in shell.nix ([bc13065](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/bc130658e97e7811c26aaa132d945c4a0258fa9c))
|
||||
* update package sdslite.oceanbox-2.7.3 ([aba0917](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/aba0917557b32ad29aabba0d9d59dd8925477a8c))
|
||||
|
||||
# [5.5.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.4.1...v5.5.0) (2023-12-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update devcontainer to net8.0 ([d75db35](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/d75db35d8bba9283091447ae08ccf9ec07213f7a))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* upgrade to net8.0 ([cfbf2b1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/cfbf2b1d61e1a68c4516ffe36c0ac28526fb88e1))
|
||||
|
||||
## [5.4.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.4.0...v5.4.1) (2023-10-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix arome variable names ([0f2b696](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/0f2b69609c5ac8d5cc1e8ddf5e2cdb8e0e2b7ef1))
|
||||
|
||||
# [5.4.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.3.0...v5.4.0) (2023-09-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bug in bbox center ([90b50c3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/90b50c3c8359536ffffb8737cde30682f079fbd3))
|
||||
* remove depricated grid.projection ([f38f06c](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/f38f06c936d92ca2598f16b56e3d7025d8efb4ae))
|
||||
* remove print ([d2e362d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/d2e362df2019f70d75a3d9a79b7f0fee3992e574))
|
||||
* rescale/translate grid ([5f5ad1b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/5f5ad1b9e41fbb502db41b9fe327ec970a1a608e))
|
||||
* update ProjNet (error on unknown proj) ([5479c8b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/5479c8b598c2c1474f86d841fad1fac8e6b431d5))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* read tauc from fvcom file ([4ca7fff](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/4ca7fff09ea4eea3a8af66bd71907de96df642c3))
|
||||
|
||||
# [5.3.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.2.0...v5.3.0) (2023-09-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add functtions to read grid in lon-lat format ([902ac08](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/902ac080e9b74167825fbccb086f99f6bad203c2))
|
||||
|
||||
# [5.2.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.1.1...v5.2.0) (2023-08-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* getTimeInDays returns single, not float ([434ab6d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/434ab6d5f43390e75f9760bd9310bbbeed678975))
|
||||
* remove FsKdTree references for faster builds ([86384bf](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/86384bfd9f64e768c93cda2b04c2787897d2b20f))
|
||||
* update deps ([460f8f1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/460f8f10eb3aed704c59eaddf587268b43373896))
|
||||
* update deps ([bb57404](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/bb5740452375984cd97139d64a8a3e5c204f6661))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add getTimeInDays to Fvcom accessors ([302c4f1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/302c4f10488cf017501427e044b6f3669fc28258))
|
||||
* add getTimsSpanSinceStart function ([764bded](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/764bdedb453c4a8e2bbec3c1cd43ed314fa08e94))
|
||||
* add Singlular module for time-series (later add Plural) ([eb2a981](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/eb2a98157653d8a7faadbcc7c6106de8befd867a))
|
||||
* read data in sigma layer blocks ([e7bb554](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/e7bb5540ef74a88efe259ef8063c46ec33af7420))
|
||||
* read necessary grid prop from file ([ff947bb](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/ff947bb3644af7d09039df5898ce825ad1ca88bf))
|
||||
* remove projection from grid(s), now in archmesiter ([36bd52d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/36bd52d3f174ea76f155c680066dca48e9d18a12))
|
||||
* upgrade to net7.0 ([2be8397](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/2be8397297e586ca7292c40dc65e0484a44483d3))
|
||||
* working arome querying ([4556a9f](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/4556a9fd9a7f8bd9f15719577336a894e2435ba8))
|
||||
|
||||
## [5.1.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.1.0...v5.1.1) (2023-02-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* compute and not read center variables ([a6a8828](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/a6a8828ae9f403469d827f767cd001f7191370b5))
|
||||
* compute and not read siglay_center ([a9d7662](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/a9d7662a2b131bb43740d8a279e4162db5a99894))
|
||||
|
||||
# [5.1.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.0.3...v5.1.0) (2023-01-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update node in devcontainer ([347a730](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/347a730e135f407d2635a29f63a25796ebf6b2fb))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add readOmega for vertical sigma velocity ([7d81ac7](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7d81ac771a0b14ba5a3da97e4986610056969ff9))
|
||||
|
||||
## [5.0.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.0.2...v5.0.3) (2023-01-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* using S_rho in readVerticalGrid ([886234b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/886234b1659a214755b8e439e99d003033f992fd))
|
||||
|
||||
## [5.0.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.0.1...v5.0.2) (2023-01-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* use S_rho as vertical roms coordinate ([f851e54](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/f851e5411b5c248385be216de1409fda68603a7b))
|
||||
|
||||
## [5.0.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v5.0.0...v5.0.1) (2022-12-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update ProjNet.FSharp ([0bf255d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/0bf255d51056bfe506d3c9da7f2765d74aa75244))
|
||||
|
||||
# [5.0.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.6.0...v5.0.0) (2022-12-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update ProjNet.FSharp ([ab63c39](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/ab63c39993906dbdf80f9fd19ec636981a348d0f))
|
||||
|
||||
# [4.6.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.5.3...v4.6.0) (2022-12-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add tryGetNode grid method ([8c1c3e7](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8c1c3e750f67d3a4c50b0a3bf1f74a8bfa792410))
|
||||
|
||||
## [4.5.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.5.2...v4.5.3) (2022-12-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* make siglev/lay readers faster ([a2b6a3b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/a2b6a3b04fa71b38beffa7c06fcdc5ae076b3299))
|
||||
|
||||
## [4.5.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.5.1...v4.5.2) (2022-11-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix obc indexing off by one ([0bf1889](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/0bf18891b26631c2a1065cf49415e59a96efe4fa))
|
||||
|
||||
## [4.5.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.5.0...v4.5.1) (2022-11-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update ProjNet.FSharp ([1939213](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/1939213ec40f0e3ca46676e97d3e9a05a42d92d1))
|
||||
|
||||
# [4.5.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.4.1...v4.5.0) (2022-11-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add functions to ger number of sigmas ([7c977ab](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7c977abaa3b7a36fade925db3aaa99122ffdb482))
|
||||
|
||||
## [4.4.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.4.0...v4.4.1) (2022-10-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* store Fvcom field as single, but use as float ([8cd202a](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8cd202a6993a7d59a138d4ccefe8251bf47dc0b2))
|
||||
|
||||
# [4.4.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.3.0...v4.4.0) (2022-10-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add readUV(W) ranges ([e2c977b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/e2c977b843552f573cb672b60c2aa78ae2db8732))
|
||||
|
||||
# [4.3.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.2.0...v4.3.0) (2022-10-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* compute circumscribed circle around element ([3c9a7a7](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/3c9a7a701ef1cdc3d168608f4d85dc2b08a8de6e))
|
||||
|
||||
# [4.2.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.1.0...v4.2.0) (2022-10-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add Fvcom.getTime ([cbe31b9](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/cbe31b94b50a6cf7a066e095af27ff073855c119))
|
||||
|
||||
# [4.1.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v4.0.0...v4.1.0) (2022-09-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* project on boundary ([0a8b31c](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/0a8b31c1f3b85ccdf9b5e108499352aabe7e0e79))
|
||||
|
||||
# [4.0.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.14.0...v4.0.0) (2022-09-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* reformat src with fantoms ([7955a76](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7955a76178cbe890901cf825bf9fc06013cf56ee))
|
||||
|
||||
# [3.14.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.13.0...v3.14.0) (2022-09-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add readUVW(s) and fix bug in readUVs ([80b2651](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/80b2651f2441b8b85037995a400c38db581c18bd))
|
||||
|
||||
# [3.13.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.12.2...v3.13.0) (2022-09-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add elemental accessors for U/V and WW ([060c775](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/060c7753a2f04cf6388a9bec62e92fe9759de6e2))
|
||||
|
||||
## [3.12.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.12.1...v3.12.2) (2022-09-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update evaluateLinearCentroid to take a readUV fvcom function ([aab00e9](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/aab00e965134814e29893ffad90246b773108a3a))
|
||||
|
||||
## [3.12.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.12.0...v3.12.1) (2022-09-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* extract node element tree from option before saving to disk ([c6175f2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/c6175f2e140e5a9dcbee16adace86a03a0e97db2))
|
||||
|
||||
# [3.12.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.11.5...v3.12.0) (2022-09-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Clough-Tocher interpolation ([8838018](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8838018ee08f32ba758fbf5662bde1e39daf7455))
|
||||
|
||||
## [3.11.5](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.11.4...v3.11.5) (2022-09-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* don't use dotnet restore lock file ([b4500ce](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/b4500ceaa6d173540515af902ef91ee5f5ea0b7d))
|
||||
* revert to C# kd-tree for now ([c857856](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/c857856b5eed122bf36ea5363bedce3bb9907eae))
|
||||
|
||||
## [3.11.4](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.11.3...v3.11.4) (2022-09-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update vendor dependencies ([5c84402](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/5c844026b61f589626e49e8edcf8d7dd56c2d7dc))
|
||||
|
||||
## [3.11.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.11.2...v3.11.3) (2022-09-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* reenable FsKdTree (test) ([856fdbe](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/856fdbee40c6fc9961d31c92239e0cc2ff025302))
|
||||
* update ProjNet.FSharp ([8e93280](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8e9328098b545c264e989fd0589b0b0b45147bad))
|
||||
* update ProjNet.FSharp ([3345ce6](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/3345ce6fbd3ad5bf4bd0a8b80290b059bc76be0b))
|
||||
|
||||
## [3.11.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.11.1...v3.11.2) (2022-09-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* submodules use https ([8782ca4](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8782ca450c84b72d170240c3929697ec09cc6a11))
|
||||
* submodules use relpath ([135def2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/135def257336183b59c1bfe5f8b1448e722b8c0a))
|
||||
* use local vendor folder with git submodules ([7c22c3b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7c22c3bdc3a6a5e245dd4b3fddb5f4b87d2d159e))
|
||||
|
||||
## [3.11.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.11.0...v3.11.1) (2022-09-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove Sdk.Web dependency ([9fa5a37](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/9fa5a37709e47d076bd73a3a80114993016612ee))
|
||||
|
||||
# [3.11.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.10.4...v3.11.0) (2022-08-29)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* evaluate 2D fields in arbitrary points ([3d63732](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/3d637324501df917adbe55845e4b5c295cd3a4d9))
|
||||
|
||||
## [3.10.4](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.10.3...v3.10.4) (2022-08-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update deps ([9382b46](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/9382b46f38ce93c97e44a02b0451eabeaf641205))
|
||||
|
||||
## [3.10.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.10.2...v3.10.3) (2022-08-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not calculate centroids on node tree ([7e41169](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7e411693d588bffa6021e1439c7d76d23acfba35))
|
||||
* do not save index tree as option ([8ba4de5](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8ba4de5bb08e547d2935abd4d123958b8380d0fa))
|
||||
|
||||
## [3.10.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.10.1...v3.10.2) (2022-07-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bug in makeNestTree ([af26509](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/af26509fa415af19bb52c18f5858f5b687c4646c))
|
||||
|
||||
## [3.10.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.10.0...v3.10.1) (2022-07-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Make tryFindElementTwice private not to confuse users ([75aa453](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/75aa45392f9771a57edc71129457678985718b2b))
|
||||
|
||||
# [3.10.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.9.0...v3.10.0) (2022-07-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add methods to pickle and unpickle neighbor index ([252141f](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/252141fea03c5028698e3efee8c4fdcb723d02fd))
|
||||
|
||||
# [3.9.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.8.3...v3.9.0) (2022-07-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* switch to FsKDTree ([0ae2652](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/0ae2652fcc7e01005d74e15823a2ea4a58e06dbd))
|
||||
|
||||
## [3.8.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.8.2...v3.8.3) (2022-07-06)
|
||||
|
||||
## [3.8.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.8.1...v3.8.2) (2022-06-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove debug prints ([a5698ff](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/a5698ff89a2979a22f95e81989351c5a4414937d))
|
||||
|
||||
## [3.8.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.8.0...v3.8.1) (2022-06-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix insideTriangle (take 2) ([7efc6a1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7efc6a1d528086ec5007c5b286561f83659df738))
|
||||
|
||||
# [3.8.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.7.0...v3.8.0) (2022-06-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix insideTriangle ([ea29fcb](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/ea29fcb6013d9516e792a349d15828b3796ae9c0))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add getNumFrames per Fvcom dataset archive ([ff268d4](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/ff268d461fcf60ee08a694054e4a8e20c590a0ac))
|
||||
|
||||
# [3.7.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.6.0...v3.7.0) (2022-06-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ExtendedGrid and refactor grids and helpers ([8143571](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/8143571a4b45d296acf7471f38ca635bf53d6fd0))
|
||||
|
||||
# [3.6.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.5.0...v3.6.0) (2022-06-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add helpers to efficiently find nearest element and more ([225754b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/225754bc4b3f743ea4278a7c49857cba2f87924e))
|
||||
|
||||
# [3.5.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.4.0...v3.5.0) (2022-06-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* track upstream ProjNet.FSharp changes ([1af2f32](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/1af2f322dd92c3486066231ae63765017eabb127))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add coordinate projection to grids ([7012d2b](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7012d2b2caed3686feebba138f13b8891444b846))
|
||||
|
||||
# [3.4.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.3.0...v3.4.0) (2022-06-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add routines to convert elemental to nodal props ([1c74935](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/1c749355fbb0eb0a28bc09f3326d2acaef9fb926))
|
||||
|
||||
# [3.3.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.2.0...v3.3.0) (2022-06-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bug fix zeta getter ([b564dec](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/b564dec305c09d8214b09aa8f7adfa97826ffeeb))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add getter for zeta ([db7fe87](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/db7fe87a5a1d21bac1da817b0d88722aa8f9d71f))
|
||||
|
||||
# [3.2.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.1.0...v3.2.0) (2022-05-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* refactor for better code structure ([b37d257](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/b37d257674750f434ea482d68f5001923ed11c14))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* bilinear interpolation ([37613cb](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/37613cb19fb4c00bf7cd266507c8a0adc00a9645))
|
||||
|
||||
# [3.1.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.0.3...v3.1.0) (2022-05-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Remove functions really belonging to Primus ([b43466f](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/b43466fb24a499d969970353822e6b08d52bca60))
|
||||
|
||||
## [3.0.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.0.2...v3.0.3) (2022-05-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove writeFvcomRestart ([f869d26](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/f869d2611b007ef5fad658504103ca2f235fc6ab))
|
||||
|
||||
## [3.0.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.0.1...v3.0.2) (2022-05-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add warning for empty kd-trees (input error) ([ecceccd](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/ecceccd29784140737be19f73e910dc9cdf4b882))
|
||||
|
||||
## [3.0.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v3.0.0...v3.0.1) (2022-05-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* generalize Grid projections ([7ebad27](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/7ebad274193469e15fad04e2e9a4ecb4102dc035))
|
||||
* update deps ([aef93d2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/aef93d2d4fa81fdee8fb8676b673bb984f964132))
|
||||
|
||||
# [3.0.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v2.1.0...v3.0.0) (2022-05-11)
|
||||
|
||||
# [2.1.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v2.0.1...v2.1.0) (2022-05-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* simplify use Grid instead of FvcomGrid where appropriate ([ee97e7d](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/ee97e7de9df75fffadedeb4d29abd0139721bdd7))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add genCells function ([d41790a](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/d41790a2be27bd64c7a2aeba5cbd1083803fdfbc))
|
||||
|
||||
## [2.0.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v2.0.0...v2.0.1) (2022-05-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove leftover trace ([5806502](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/58065024ffa3606f2b3e97486eb1b9670ff9ea62))
|
||||
|
||||
# [2.0.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v1.2.3...v2.0.0) (2022-05-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add function to get nbve from fvcom archive ([26524f1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/26524f11367289f6bb4a5bde76d089015a4b5979))
|
||||
* add trace function ([cfaca7e](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/cfaca7ed501c2026c66b588cd94f0ef0ba7ea49b))
|
||||
* compute art1 and art2 ([6e75e02](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/6e75e0282ff261ece5ed647174202ce4ba8672d1))
|
||||
|
||||
## [1.2.3](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v1.2.2...v1.2.3) (2022-05-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix two bugs, one subtle, one stupid. ([e438f7a](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/e438f7a885c1a63ddb4d168e587cbc9e8284435c))
|
||||
|
||||
## [1.2.2](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v1.2.1...v1.2.2) (2022-04-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update sdslite to 2.30 ([b183a1a](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/b183a1af05f8a2f430b7357c15ae07cb844c8f9b))
|
||||
|
||||
## [1.2.1](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v1.2.0...v1.2.1) (2022-04-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* only distinct boundary nodes ([9ee8373](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/9ee83739bf593db874108d27580d058c2272ceaf))
|
||||
|
||||
# [1.2.0](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/compare/v1.1.0...v1.2.0) (2022-04-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add boundary nodes and element functions ([b532951](https://gitlab.com/oceanbox/Oceanbox.FvcomKit/commit/b532951e854864f7eab66abda1cd32362e027461))
|
||||
|
||||
# [1.1.0](https://gitlab.com/oceanbox/Oceabox.FvcomKit/compare/v1.0.0...v1.1.0) (2022-04-26)
|
||||
|
||||
|
||||
|
||||
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";
|
||||
}
|
||||
10009
package-lock.json
generated
10009
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
25
shell.nix
Normal file
25
shell.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
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
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
netcdf
|
||||
stdenv.cc.cc.lib
|
||||
];
|
||||
|
||||
DOTNET_ROOT = "${dotnet-sdk}/share/dotnet";
|
||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
|
||||
}
|
||||
309
src/Adjoin.fs
Normal file
309
src/Adjoin.fs
Normal file
@@ -0,0 +1,309 @@
|
||||
module Oceanbox.FvcomKit.Adjoin
|
||||
|
||||
open FSharpPlus
|
||||
//open FsKDTree
|
||||
open ProjNet.FSharp
|
||||
open Grid
|
||||
open Types
|
||||
open Polygon
|
||||
open KdTree // C# version
|
||||
|
||||
type CropBox = (float * float) * (float * float)
|
||||
type Mask = bool[,]
|
||||
type Pos = float * float
|
||||
type PosVec = Pos[]
|
||||
type BiPos = float[,] * float[,]
|
||||
|
||||
let private reProject (proj: IProj) ((lng, lat): BiPos) =
|
||||
lng
|
||||
|> Array2D.mapi (fun i j lon -> lon, lat[i, j])
|
||||
|> Array2D.map proj.project
|
||||
|> unzip2D
|
||||
|
||||
let private genCropIdx ((min, max): float * float) (m: float[,]) =
|
||||
[|
|
||||
for i = 0 to Array2D.length1 m - 1 do
|
||||
for j = 0 to Array2D.length2 m - 1 do
|
||||
if m[i, j] >= min && m[i, j] <= max then i, j else ()
|
||||
|]
|
||||
|> Set.ofArray
|
||||
|
||||
let private genCropMask ((xlim, ylim): CropBox) ((x, y): BiPos) =
|
||||
let ind1 = genCropIdx xlim x
|
||||
let ind2 = genCropIdx ylim y
|
||||
Set.intersect ind1 ind2 |> Set.toArray
|
||||
|
||||
// compute a padded fvcom bounding box for cropping roms grids
|
||||
let private mkCropBox (box: BBox) : CropBox =
|
||||
let pad min max =
|
||||
let d = 5000.0
|
||||
float min - d, float max + d
|
||||
let xlim = pad box.minX box.maxX
|
||||
let ylim = pad box.minY box.maxY
|
||||
xlim, ylim
|
||||
|
||||
// make an array of indeces of wet roms grid points inside the fvcom domain
|
||||
let private genCullIdx (box: CropBox) (wet: Mask) (p: BiPos) =
|
||||
genCropMask box p |> Array.filter (fun (i, j) -> wet[i, j])
|
||||
|
||||
// crop roms grid coordinates based in index mask of active, overlapping points
|
||||
let private cullCoords (p: BiPos) (idx: (int * int)[]) =
|
||||
let x, y = p
|
||||
let x' = idx |> Array.map (fun (i, j) -> x[i, j])
|
||||
let y' = idx |> Array.map (fun (i, j) -> y[i, j])
|
||||
Array.zip x' y'
|
||||
|
||||
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)
|
||||
if points.Length > 0 then
|
||||
tree.Balance ()
|
||||
else
|
||||
// Log.Warning $"Empty kd-tree"
|
||||
()
|
||||
tree
|
||||
|
||||
// make a kd-tree for fast nearest neighbour lookup
|
||||
let private buildTree (points: (float * float) array) =
|
||||
points
|
||||
|> Array.mapi (fun n (x, y) -> { Pos = x, y; Data = n })
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createTree
|
||||
|
||||
// adjoinIdx: index to culled roms grid for each fvcom node
|
||||
// cullIdx: index to roms points _actually_ in use
|
||||
// oobIdx: out-of-bounds points, too far from a roms cell
|
||||
type FvcomAdjoint = { adjoinIdx: int[]; cullIdx: (int * int)[]; oobIdx: int[] }
|
||||
|
||||
let private dist (a: float * float) (b: float * float) =
|
||||
let x0, y0 = a
|
||||
let x1, y1 = b
|
||||
let dX = x1 - x0
|
||||
let dY = y1 - y0
|
||||
dX ** 2 + dY ** 2 |> sqrt |> (*) 0.5
|
||||
|
||||
let private distLngLat (proj: IProj) (a: float * float) (b: float * float) =
|
||||
let x0, y0 = a |> proj.project
|
||||
let x1, y1 = b |> proj.project
|
||||
let dX = x1 - x0
|
||||
let dY = y1 - y0
|
||||
dX ** 2 + dY ** 2 |> sqrt |> (*) 0.5
|
||||
|
||||
// let private genOobIdx (proj: IProj) (tree: Tree<_, _>) (cullIdx: (int * int) []) (fPos: PosVec) (rPos: BiPos) =
|
||||
// let rLon, rLat = rPos
|
||||
// let dMax =
|
||||
// distLngLat proj (rLon[0, 0], rLat[0, 0]) (rLon[0, 1], rLat[0, 1])
|
||||
// fPos
|
||||
// |> Array.fold
|
||||
// (fun (n, a) (x, y as p0) ->
|
||||
// nearestNeighbor tree { X = x; Y = y }
|
||||
// |> fun p ->
|
||||
// let i0, i1 = cullIdx[p.Value.Data]
|
||||
// let p1 = proj.project ((rLon[i0, i1], rLat[i0, i1]))
|
||||
// let d = dist p0 p1
|
||||
// if d > dMax then n + 1, n :: a else n + 1, a)
|
||||
// (0, [])
|
||||
// |> snd
|
||||
// |> Array.ofList
|
||||
let private genOobIdx (proj: IProj) (tree: KdTree<_, _>) (cullIdx: (int * int)[]) (fPos: PosVec) (rPos: BiPos) =
|
||||
let rLon, rLat = rPos
|
||||
let dMax = distLngLat proj (rLon[0, 0], rLat[0, 0]) (rLon[0, 1], rLat[0, 1])
|
||||
fPos
|
||||
|> Array.fold
|
||||
(fun (n, a) (x, y as p0) ->
|
||||
tree.GetNearestNeighbours ([| x; y |], 1)
|
||||
|> Array.head
|
||||
|> fun p ->
|
||||
let i0, i1 = cullIdx[p.Value]
|
||||
let p1 = proj.project ((rLon[i0, i1], rLat[i0, i1]))
|
||||
let d = dist p0 p1
|
||||
if d > dMax then n + 1, n :: a else n + 1, a)
|
||||
(0, [])
|
||||
|> snd
|
||||
|> Array.ofList
|
||||
|
||||
// compute the nearest neighbour index into the cropped roms grid
|
||||
// let private mkFvcomAdjoint (proj: IProj) (fPos: PosVec) (bbox: BBox) ((rPos, wet): BiPos * Mask) =
|
||||
// let box = mkCropBox bbox
|
||||
// let pos' = reProject proj rPos
|
||||
// let cullIdx = genCullIdx box wet pos'
|
||||
// let tree = cullCoords pos' cullIdx |> buildTree
|
||||
// let nearest =
|
||||
// fPos
|
||||
// |> Array.map (fun (x, y) ->
|
||||
// nearestNeighbor tree { X = x; Y = y }
|
||||
// |> fun x -> x.Value.Data)
|
||||
// {
|
||||
// adjoinIdx = nearest
|
||||
// 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
|
||||
let cullIdx = genCullIdx box wet pos'
|
||||
let tree = cullCoords pos' cullIdx |> buildTree
|
||||
let nearest =
|
||||
fPos
|
||||
|> Array.map (fun (x, y) -> tree.GetNearestNeighbours ([| x; y |], 1) |> Array.head |> (fun x -> x.Value))
|
||||
let oobIdx = genOobIdx proj tree cullIdx fPos rPos
|
||||
|
||||
{ adjoinIdx = nearest; cullIdx = cullIdx; oobIdx = oobIdx }
|
||||
|
||||
let inline float2 x = bimap float float x
|
||||
|
||||
let getNearestNode (proj: IProj) (fvcom: Grid) (roms: BiPos * Mask) =
|
||||
let fvNodes = Array.map float2 fvcom.Nodes
|
||||
mkFvcomAdjoint proj fvNodes fvcom.BBox roms
|
||||
|
||||
// same as getNearestNode, but for uv in the center of a cell/element
|
||||
let getNearestCell (proj: IProj) (fvcom: Grid) (roms: BiPos * Mask) =
|
||||
let cells = Util.calcCentroids fvcom |> Array.map float2
|
||||
mkFvcomAdjoint proj cells fvcom.BBox roms
|
||||
|
||||
let private createIdxTree (points: Leaf<int * int>[]) =
|
||||
let tree = KdTree<float, int * int> (2, KdTree.Math.DoubleMath ())
|
||||
points
|
||||
|> Array.iter (fun a -> tree.Add ([| fst a.Pos; snd a.Pos |], a.Data) |> ignore)
|
||||
if points.Length > 0 then
|
||||
tree.Balance ()
|
||||
else
|
||||
//Log.Warning $"Empty kd-tree"
|
||||
()
|
||||
tree
|
||||
|
||||
// rPos must be in the right projection!
|
||||
let makeNestTree ((lng, lat): float[,] * float[,]) =
|
||||
[| 0 .. (Array2D.length1 lng) - 1 |]
|
||||
|> Array.map (fun i ->
|
||||
[| 0 .. (Array2D.length2 lng) - 1 |]
|
||||
|> Array.map (fun j ->
|
||||
let x = lng[i, j]
|
||||
let y = lat[i, j]
|
||||
{ Pos = x, y; Data = (i, j) }))
|
||||
|> Array.concat
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createIdxTree
|
||||
|
||||
let getNearestUpperLeft' (tree: KdTree<float, int * int>) (((ew, ns), mask): BiPos * Mask) ((x, y): float * float) =
|
||||
let i, j =
|
||||
// nearestNeighbor tree { X = x; Y = y }
|
||||
tree.GetNearestNeighbours ([| x; y |], 1) |> fun x -> x[0].Value
|
||||
let p1 = [|
|
||||
ew[i, j], ns[i, j]
|
||||
ew[i + 1, j], ns[i + 1, j]
|
||||
ew[i + 1, j - 1], ns[i + 1, j - 1]
|
||||
ew[i, j - 1], ns[i, j - 1]
|
||||
|] // lower right grid cell
|
||||
let p2 = [|
|
||||
ew[i, j], ns[i, j]
|
||||
ew[i + 1, j], ns[i + 1, j]
|
||||
ew[i + 1, j + 1], ns[i + 1, j + 1]
|
||||
ew[i, j + 1], ns[i, j + 1]
|
||||
|] // upper right grid cell
|
||||
let p3 = [|
|
||||
ew[i, j], ns[i, j]
|
||||
ew[i - 1, j], ns[i - 1, j]
|
||||
ew[i - 1, j - 1], ns[i - 1, j - 1]
|
||||
ew[i, j - 1], ns[i, j - 1]
|
||||
|] // lower left grid cell
|
||||
let p4 = [|
|
||||
ew[i, j], ns[i, j]
|
||||
ew[i - 1, j], ns[i - 1, j]
|
||||
ew[i - 1, j + 1], ns[i - 1, j + 1]
|
||||
ew[i, j + 1], ns[i, j + 1]
|
||||
|] // upper left grid cell
|
||||
let q =
|
||||
if inpolygon p1 (x, y) then
|
||||
[| i + 1, j - 1; i + 1, j; i, j; i, j - 1 |]
|
||||
elif inpolygon p2 (x, y) then
|
||||
[| i + 1, j; i + 1, j + 1; i, j + 1; i, j |]
|
||||
elif inpolygon p3 (x, y) then
|
||||
[| i, j - 1; i, j; i - 1, j; i - 1, j - 1 |]
|
||||
elif inpolygon p4 (x, y) then
|
||||
[| i, j; i, j + 1; i - 1, j + 1; i - 1, j |]
|
||||
else
|
||||
[| 0, 0; 0, 0; 0, 0; 0, 0 |]
|
||||
if (q |> Array.map (fun (q1, q2) -> q1 + q2) |> Array.sum) = 0 then
|
||||
failwith "Surrounding grid cell not found"
|
||||
let m = q |> Array.map (fun (n, m) -> mask[n, m])
|
||||
Array.zip q m
|
||||
|
||||
// TODO: this is the F# Kd-tree version, which is currently defunct
|
||||
// let getNearestUpperLeft
|
||||
// (tree: Tree<Leaf<float, int * int> [], Node<float>>)
|
||||
// (((ew, ns), mask): BiPos * Mask)
|
||||
// ((x, y): float * float)
|
||||
// =
|
||||
// let i, j =
|
||||
// nearestNeighbor tree { X = x; Y = y }
|
||||
// |> fun x -> x.Value.Data
|
||||
// let p1 =
|
||||
// [|
|
||||
// ew[i, j], ns[i, j]
|
||||
// ew[i + 1, j], ns[i + 1, j]
|
||||
// ew[i + 1, j - 1], ns[i + 1, j - 1]
|
||||
// ew[i, j - 1], ns[i, j - 1]
|
||||
// |] // lower right grid cell
|
||||
// let p2 =
|
||||
// [|
|
||||
// ew[i, j], ns[i, j]
|
||||
// ew[i + 1, j], ns[i + 1, j]
|
||||
// ew[i + 1, j + 1], ns[i + 1, j + 1]
|
||||
// ew[i, j + 1], ns[i, j + 1]
|
||||
// |] // upper right grid cell
|
||||
// let p3 =
|
||||
// [|
|
||||
// ew[i, j], ns[i, j]
|
||||
// ew[i - 1, j], ns[i - 1, j]
|
||||
// ew[i - 1, j - 1], ns[i - 1, j - 1]
|
||||
// ew[i, j - 1], ns[i, j - 1]
|
||||
// |] // lower left grid cell
|
||||
// let p4 =
|
||||
// [|
|
||||
// ew[i, j], ns[i, j]
|
||||
// ew[i - 1, j], ns[i - 1, j]
|
||||
// ew[i - 1, j + 1], ns[i - 1, j + 1]
|
||||
// ew[i, j + 1], ns[i, j + 1]
|
||||
// |] // upper left grid cell
|
||||
// let q =
|
||||
// if inpolygon p1 (x, y) then
|
||||
// [| i + 1, j - 1; i + 1, j; i, j; i, j - 1 |]
|
||||
// elif inpolygon p2 (x, y) then
|
||||
// [| i + 1, j; i + 1, j + 1; i, j + 1; i, j |]
|
||||
// elif inpolygon p3 (x, y) then
|
||||
// [| i, j - 1; i, j; i - 1, j; i - 1, j - 1 |]
|
||||
// elif inpolygon p4 (x, y) then
|
||||
// [| i, j; i, j + 1; i - 1, j + 1; i - 1, j |]
|
||||
// else
|
||||
// [| 0, 0; 0, 0; 0, 0; 0, 0 |]
|
||||
// if (q
|
||||
// |> Array.map (fun (q1, q2) -> q1 + q2)
|
||||
// |> Array.sum) = 0 then
|
||||
// failwith "Surrounding grid cell not found"
|
||||
// let m = q |> Array.map (fun (n, m) -> mask[n, m])
|
||||
// Array.zip q m
|
||||
|
||||
let getNearestCellCorner (coords, _ as grid: BiPos * Mask) (pos: (float * float)[]) =
|
||||
let tree = makeNestTree coords
|
||||
// pos |> Array.map (getNearestUpperLeft tree grid)
|
||||
pos |> Array.map (getNearestUpperLeft' tree grid)
|
||||
|
||||
let getCellBox ((ew, ns): BiPos) (boxid: ((int * int) * bool)[]) =
|
||||
boxid
|
||||
|> Array.map (fun ((n, m), mask) -> (ew[n, m], ns[n, m]), mask)
|
||||
|> Array.unzip
|
||||
|
||||
let getCellProps (prop: float[,]) ((n, m): int * int) =
|
||||
prop[n, m], prop[n + 1, m], prop[n + 1, m + 1], prop[n + 1, m]
|
||||
|
||||
// pick out elements actually in use
|
||||
let inline private cullBiMatrix (culler: (int * int)[]) (m: 'a[,]) =
|
||||
culler |> Array.map (fun (i, j) -> m[i, j])
|
||||
|
||||
// adjoin fvcom and roms data based on nearest neighbours
|
||||
let adjoinMatrix (adj: FvcomAdjoint) (m: 'a[,]) =
|
||||
let x = cullBiMatrix adj.cullIdx m
|
||||
adj.adjoinIdx |> Array.map (fun n -> x[n])
|
||||
260
src/Arome.fs
Normal file
260
src/Arome.fs
Normal file
@@ -0,0 +1,260 @@
|
||||
module Oceanbox.FvcomKit.Arome
|
||||
|
||||
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 = {
|
||||
dimensions = 0, 0
|
||||
BBox = BBox.empty
|
||||
squareSize = 0.0
|
||||
projection = CoordSys.LCCMet ()
|
||||
points = Array.empty
|
||||
}
|
||||
|
||||
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 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
|
||||
maxX = maxX
|
||||
minY = minY
|
||||
maxY = maxY
|
||||
center = center
|
||||
}
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
BBox.empty
|
||||
|
||||
/// 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
|
||||
let ys = (ds["y"].GetData () :?> single[]) |> Array.map float
|
||||
let bbox = getBBox xs ys
|
||||
|
||||
if xs.Length < 2 && ys.Length < 2 then
|
||||
Error "The dataset must contain at least 1 square"
|
||||
else
|
||||
let x0, y0 = xs[0], ys[0]
|
||||
let x1, y1 = xs[1], ys[1]
|
||||
let lengthX = if x1 > x0 then x1 - x0 else x0 - x1
|
||||
let lengthY = if y1 > y0 then y1 - y0 else y0 - y1
|
||||
let isSquare = lengthX = lengthY
|
||||
|
||||
if isSquare then
|
||||
{ SquareGrid.empty with dimensions = dimensions; BBox = bbox; squareSize = lengthX }
|
||||
|> Ok
|
||||
else
|
||||
Log.Error (
|
||||
"FvcomKit.Arome.getGrid grid is not square: {X1} - {X0} = {LengthX} = {LengthY} = {Y1} - {Y0}",
|
||||
x1,
|
||||
x0,
|
||||
lengthX,
|
||||
lengthY,
|
||||
y1,
|
||||
y0
|
||||
)
|
||||
Error "The given data set does not contain a grid made up of squares"
|
||||
with exn ->
|
||||
Log.Error (exn, "FvcomKit.Arome.getGrid exception")
|
||||
Error $"Error reading arome grid: {exn.Message}"
|
||||
|
||||
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 (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}",
|
||||
(bbox.minX, bbox.minY),
|
||||
(bbox.maxX, bbox.maxY),
|
||||
(x0, y0),
|
||||
(dx, dy),
|
||||
(xIdx, yIdx)
|
||||
)
|
||||
None
|
||||
else
|
||||
None
|
||||
|
||||
/// Tries to get the closest x and y in the arome dataset based on position p
|
||||
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 p
|
||||
651
src/Fvcom.fs
651
src/Fvcom.fs
@@ -2,156 +2,486 @@ module Oceanbox.FvcomKit.Fvcom
|
||||
|
||||
#nowarn "57"
|
||||
|
||||
open System
|
||||
open Microsoft.Research.Science.Data
|
||||
open FSharpPlus
|
||||
open Serilog
|
||||
open Grid
|
||||
|
||||
type FvcomRestart =
|
||||
{
|
||||
salinity: single [,,]
|
||||
temp: single [,,]
|
||||
zeta: single [,]
|
||||
u: single [,,]
|
||||
v: single [,,]
|
||||
ua: single [,]
|
||||
va: single [,]
|
||||
open Types
|
||||
|
||||
type FvcomGrid = {
|
||||
Elem: Elem array
|
||||
Nodes: Node array
|
||||
BBox: BBox
|
||||
Cells: Node array
|
||||
Bathymetry: single[]
|
||||
Siglay: single[,]
|
||||
SiglayCenter: single[,]
|
||||
Siglev: single[,]
|
||||
} with
|
||||
interface IGrid with
|
||||
member this.getVertex n = this.Nodes[n]
|
||||
member this.getCell n = this.Elem[n]
|
||||
member this.getCellVertices n =
|
||||
let a, b, c = this.Elem[n]
|
||||
this.Nodes[a], this.Nodes[b], this.Nodes[c]
|
||||
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
|
||||
Cells = Array.empty
|
||||
Bathymetry = Array.empty
|
||||
Siglay = Array2D.zeroCreate 0 0
|
||||
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) =
|
||||
try
|
||||
ds.Dimensions["time"].Length
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
0
|
||||
|
||||
let getNumSiglay (ds: DataSet) =
|
||||
try
|
||||
ds.Dimensions["siglay"].Length
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
0
|
||||
|
||||
let getNumSiglev (ds: DataSet) =
|
||||
try
|
||||
ds.Dimensions["siglev"].Length
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
0
|
||||
|
||||
let getTime (ds: DataSet) n =
|
||||
try
|
||||
let ts = ds["Times"].GetData () :?> byte[,]
|
||||
|
||||
ts[n, *] |> Array.map char |> System.String |> System.DateTime.Parse |> Some
|
||||
with e ->
|
||||
Log.Error $"getTime exception: {e.Message}"
|
||||
None
|
||||
|
||||
let getTimeSpanSinceStart (ds: DataSet) n =
|
||||
try
|
||||
let days = ds["Itime"].GetData () :?> int[]
|
||||
let msec = ds["Itime2"].GetData () :?> int[]
|
||||
let t0 = TimeSpan.FromDays days[n]
|
||||
let t1 = TimeSpan.FromMilliseconds (float msec[n])
|
||||
t0 + t1 |> Some
|
||||
with e ->
|
||||
Log.Error $"getTimeInDays exception: {e.Message}"
|
||||
None
|
||||
|
||||
let readTauc (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let tauc = ds["tauc"].GetData ([| t; 0 |], [| 1; n |]) :?> single[,]
|
||||
tauc[0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readUV (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let u = ds[ "u" ].GetData([| t; l; 0 |], [| 1; 1; n |]) :?> single [,,]
|
||||
let v = ds[ "v" ].GetData([| t; l; 0 |], [| 1; 1; n |]) :?> single [,,]
|
||||
let u = ds["u"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
Array.zip u[0, 0, *] v[0, 0, *]
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readUV' (ds: DataSet) t l =
|
||||
readUV ds t l
|
||||
|> Array.collect (fun (x, y) -> [| x; y |])
|
||||
readUV ds t l |> Array.collect (fun (x, y) -> [| x; y |])
|
||||
|
||||
let readUVs (ds: DataSet) t l es =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let u = ds["u"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let u' = es |> Array.map (fun i -> u[0, 0, i])
|
||||
let v' = es |> Array.map (fun i -> v[0, 0, i])
|
||||
Array.zip u' v'
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
/// <summary>
|
||||
/// Reads properties 'u' and 'v' from FVCOM dataset at the given time and depth.
|
||||
/// </summary>
|
||||
/// <param name="ds">The NetCDF dataset to open</param>
|
||||
/// <param name="t">The given time frame</param>
|
||||
/// <param name="l">The layer of depth from where to read the values</param>
|
||||
/// <param name="e0">The starting index of the uv range</param>
|
||||
/// <param name="en">The ending index</param>
|
||||
/// <returns>Array of tuples, and empty on any errors.</returns>
|
||||
let readUVRange (ds: DataSet) t l e0 en =
|
||||
try
|
||||
let u = ds["u"].GetData ([| t; l; e0 |], [| 1; 1; en |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; l; e0 |], [| 1; 1; en |]) :?> single[,,]
|
||||
Array.zip u[0, 0, *] v[0, 0, *]
|
||||
with e ->
|
||||
Log.Error (
|
||||
e,
|
||||
"FvcomKit.Fvcom.readUVRange exception with input: time {Time}, layer {Layer}, starting elem {Elem0} and ending elem {ElemN}",
|
||||
t,
|
||||
l,
|
||||
e0,
|
||||
en
|
||||
)
|
||||
Array.empty
|
||||
|
||||
let readOmega (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let omega = ds["omega"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
omega[0, 0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readOmegaBlock (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let l = ds.Dimensions["siglev"].Length
|
||||
let u = ds["omega"].GetData ([| t; 0; 0 |], [| 1; l; n |]) :?> single[,,]
|
||||
u[0, *, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
let readOmegas (ds: DataSet) t l es =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let omega = ds["omega"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
es |> Array.map (fun i -> omega[0, 0, i])
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readU (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let u = ds["u"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
u[0, 0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readUBlock (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let u = ds["u"].GetData ([| t; 0; 0 |], [| 1; l; n |]) :?> single[,,]
|
||||
u[0, *, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
let readV (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let v = ds["v"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
v[0, 0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readVBlock (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let v = ds["v"].GetData ([| t; 0; 0 |], [| 1; l; n |]) :?> single[,,]
|
||||
v[0, *, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
let readWw (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let ww = ds["ww"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
ww[0, 0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readWwBlock (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let w = ds["ww"].GetData ([| t; 0; 0 |], [| 1; l; n |]) :?> single[,,]
|
||||
w[0, *, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
let readWws (ds: DataSet) t l es =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let ww = ds["ww"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
es |> Array.map (fun i -> ww[0, 0, i])
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readUVW (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let u = ds["u"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let w = ds["ww"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
Array.zip3 u[0, 0, *] v[0, 0, *] w[0, 0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readUVWs (ds: DataSet) t l es =
|
||||
try
|
||||
let n = ds.Dimensions["nele"].Length
|
||||
let u = ds["u"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let w = ds["ww"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
let u' = es |> Array.map (fun i -> u[0, 0, i])
|
||||
let v' = es |> Array.map (fun i -> v[0, 0, i])
|
||||
let w' = es |> Array.map (fun i -> w[0, 0, i])
|
||||
Array.zip3 u' v' w'
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readUVWRange (ds: DataSet) t l e0 en =
|
||||
try
|
||||
let u = ds["u"].GetData ([| t; l; e0 |], [| 1; 1; en |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; l; e0 |], [| 1; 1; en |]) :?> single[,,]
|
||||
let w = ds["ww"].GetData ([| t; l; e0 |], [| 1; 1; en |]) :?> single[,,]
|
||||
Array.zip3 u[0, 0, *] v[0, 0, *] w[0, 0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readTemp (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let temp =
|
||||
ds[ "temp" ].GetData([| t; l; 0 |], [| 1; 1; n |]) :?> single [,,]
|
||||
let temp = ds["temp"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
temp[0, 0, *]
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readTempBlock (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let sal = ds["temp"].GetData ([| t; 0; 0 |], [| 1; l; n |]) :?> single[,,]
|
||||
sal[0, *, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
let readSalinity (ds: DataSet) t l =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let sal =
|
||||
ds["salinity"]
|
||||
.GetData([| t; l; 0 |], [| 1; 1; n |])
|
||||
:?> single [,,]
|
||||
let sal = ds["salinity"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
sal[0, 0, *]
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readSalinityBlock (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let sal = ds["salinity"].GetData ([| t; 0; 0 |], [| 1; l; n |]) :?> single[,,]
|
||||
sal[0, *, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
|
||||
let readArt1 (ds: DataSet) =
|
||||
try
|
||||
ds[ "art1" ].GetData() :?> single []
|
||||
with
|
||||
| e ->
|
||||
ds["art1"].GetData () :?> single[]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readZeta (ds: DataSet) t =
|
||||
try
|
||||
let n = ds.Dimensions["node"].Length
|
||||
let zeta = ds["zeta"].GetData ([| t; 0 |], [| 1; n |]) :?> single[,]
|
||||
zeta[0, *]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readBathymetry (ds: DataSet) =
|
||||
try
|
||||
ds[ "h" ].GetData() :?> single []
|
||||
with
|
||||
| e ->
|
||||
ds["h"].GetData () :?> single[]
|
||||
with e ->
|
||||
Log.Error e.Message
|
||||
Array.empty
|
||||
|
||||
let tryReadBathymetry (ds: DataSet) =
|
||||
if ds.Variables.Contains "h" then
|
||||
ds["h"].GetData () :?> single[] |> Some
|
||||
else
|
||||
None
|
||||
|
||||
let readBathymetryAtCenters (ds: DataSet) =
|
||||
let h = readBathymetry ds
|
||||
let lc = ds.Dimensions["nele"].Length
|
||||
try
|
||||
let nv = ds["nv"].GetData () :?> int[,] |> Array2D.map (fun n -> n - 1)
|
||||
[| 0 .. lc - 1 |]
|
||||
|> Array.map (fun i -> (h[nv[0, i]] + h[nv[1, i]] + h[nv[2, i]]) / 3.0f)
|
||||
with e ->
|
||||
Log.Error e.Message
|
||||
Array.empty
|
||||
|
||||
let readBathymetryAtCenter (ds: DataSet) e =
|
||||
try
|
||||
let h = ds[ "h_center" ].GetData() :?> single []
|
||||
let h = readBathymetryAtCenters ds
|
||||
h[e]
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error e.Message
|
||||
-1f
|
||||
|
||||
let readSiglev (ds: DataSet) n =
|
||||
try
|
||||
let siglev = ds[ "siglev" ].GetData() :?> single [,]
|
||||
siglev[*, n]
|
||||
with
|
||||
| err ->
|
||||
let l = ds.Dimensions["siglev"].Length
|
||||
let siglev = ds["siglev"].GetData ([| 0; n |], [| l; 1 |]) :?> single[,]
|
||||
siglev[*, 0]
|
||||
with err ->
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
|
||||
let tryReadSiglev (ds: DataSet) n =
|
||||
if ds.Variables.Contains "siglev" then
|
||||
let l = ds.Dimensions["siglev"].Length
|
||||
let siglev = ds["siglev"].GetData ([| 0; n |], [| l; 1 |]) :?> single[,]
|
||||
Some siglev[*, 0]
|
||||
else
|
||||
None
|
||||
|
||||
let readSiglay (ds: DataSet) n =
|
||||
try
|
||||
let siglay = ds[ "siglay" ].GetData() :?> single [,]
|
||||
siglay[*, n]
|
||||
with
|
||||
| err ->
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let siglay = ds["siglay"].GetData ([| 0; n |], [| l; 1 |]) :?> single[,]
|
||||
siglay[*, 0]
|
||||
with err ->
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
|
||||
let readSiglayCenter (ds: DataSet) n =
|
||||
try
|
||||
let siglay = ds[ "siglay_center" ].GetData() :?> single [,]
|
||||
siglay[*, n]
|
||||
with
|
||||
| err ->
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
let tryReadSiglay (ds: DataSet) n =
|
||||
if ds.Variables.Contains "siglay" then
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let siglay = ds["siglay"].GetData ([| 0; n |], [| l; 1 |]) :?> single[,]
|
||||
Some siglay[*, 0]
|
||||
else
|
||||
None
|
||||
|
||||
let readSiglevAtCenter (ds: DataSet) e =
|
||||
try
|
||||
let siglev = ds[ "siglev_center" ].GetData() :?> single [,]
|
||||
siglev[*, e]
|
||||
with
|
||||
| e ->
|
||||
let nv = ds["nv"].GetData () :?> int[,] |> Array2D.map (fun n -> n - 1)
|
||||
let s1 = readSiglev ds nv[0, e]
|
||||
let s2 = readSiglev ds nv[1, e]
|
||||
let s3 = readSiglev ds nv[2, e]
|
||||
[| 0 .. s1.Length - 1 |] |> Array.map (fun i -> (s1[i] + s2[i] + s3[i]) / 3.0f)
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let readSiglayAtCenter (ds: DataSet) e =
|
||||
try
|
||||
let siglay = ds[ "siglay_center" ].GetData() :?> single [,]
|
||||
siglay[*, e]
|
||||
with
|
||||
| e ->
|
||||
let nv = ds["nv"].GetData () :?> int[,] |> Array2D.map (fun n -> n - 1)
|
||||
let s1 = readSiglay ds nv[0, e]
|
||||
let s2 = readSiglay ds nv[1, e]
|
||||
let s3 = readSiglay ds nv[2, e]
|
||||
[| 0 .. s1.Length - 1 |] |> Array.map (fun i -> (s1[i] + s2[i] + s3[i]) / 3.0f)
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array.empty
|
||||
|
||||
let tryReadSiglayAtCenter (ds: DataSet) e =
|
||||
if ds.Variables.Contains "siglay" then
|
||||
let nv = ds["nv"].GetData () :?> int[,] |> Array2D.map (fun n -> n - 1)
|
||||
let s1 = readSiglay ds nv[0, e]
|
||||
let s2 = readSiglay ds nv[1, e]
|
||||
let s3 = readSiglay ds nv[2, e]
|
||||
[| 0 .. s1.Length - 1 |]
|
||||
|> Array.map (fun i -> (s1[i] + s2[i] + s3[i]) / 3.0f)
|
||||
|> Some
|
||||
else
|
||||
None
|
||||
|
||||
// deprecated
|
||||
let readSiglayCenter = readSiglayAtCenter
|
||||
|
||||
module Siglay =
|
||||
let readSiglay (ds: DataSet) =
|
||||
try
|
||||
ds[ "siglay" ].GetData() :?> single [,]
|
||||
with
|
||||
| err ->
|
||||
ds["siglay"].GetData () :?> single[,]
|
||||
with err ->
|
||||
Log.Error $"{err}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
let tryReadSiglay (ds: DataSet) =
|
||||
if ds.Variables.Contains "siglay" then
|
||||
ds["siglay"].GetData () :?> single[,] |> Some
|
||||
else
|
||||
None
|
||||
|
||||
let readSiglayAtCenter (ds: DataSet) =
|
||||
let siglay = readSiglay ds
|
||||
try
|
||||
ds[ "siglay_center" ].GetData() :?> single [,]
|
||||
with
|
||||
| e ->
|
||||
let nv = ds["nv"].GetData () :?> int[,] |> Array2D.map (fun n -> n - 1)
|
||||
let l1 = Array2D.length1 siglay
|
||||
let l2 = Array2D.length2 nv
|
||||
let sc = Array2D.zeroCreate l1 l2
|
||||
sc
|
||||
|> Array2D.mapi (fun i j _ -> (siglay[i, nv[0, j]] + siglay[i, nv[1, j]] + siglay[i, nv[2, j]]) / 3.0f)
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Array2D.zeroCreate 0 0
|
||||
|
||||
let tryReadSiglayAtCenter (ds: DataSet) =
|
||||
if ds.Variables.Contains "siglay" then
|
||||
readSiglayAtCenter ds |> Some
|
||||
else
|
||||
None
|
||||
|
||||
let readUv (ds: DataSet) e t =
|
||||
try
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let u = ds[ "u" ].GetData([| t; 0; e |], [| 1; l; 1 |]) :?> single [,,]
|
||||
let v = ds[ "v" ].GetData([| t; 0; e |], [| 1; l; 1 |]) :?> single [,,]
|
||||
let u = ds["u"].GetData ([| t; 0; e |], [| 1; l; 1 |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; 0; e |], [| 1; l; 1 |]) :?> single[,,]
|
||||
Array.zip u[0, *, 0] v[0, *, 0]
|
||||
with
|
||||
| err ->
|
||||
with err ->
|
||||
Log.Warning $"readUv {e} {t}"
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
|
||||
let readUvw (ds: DataSet) e t =
|
||||
try
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let u = ds["u"].GetData ([| t; 0; e |], [| 1; l; 1 |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; 0; e |], [| 1; l; 1 |]) :?> single[,,]
|
||||
let w = ds["ww"].GetData ([| t; 0; e |], [| 1; l; 1 |]) :?> single[,,]
|
||||
Array.zip3 u[0, *, 0] v[0, *, 0] w[0, *, 0]
|
||||
with err ->
|
||||
Log.Warning $"readUv {e} {t}"
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
@@ -159,12 +489,10 @@ module Siglay =
|
||||
let readUv' (ds: DataSet) e t =
|
||||
try
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let u = ds[ "u" ].GetData([| t; 0; e |], [| 1; l; 1 |]) :?> single [,,]
|
||||
let v = ds[ "v" ].GetData([| t; 0; e |], [| 1; l; 1 |]) :?> single [,,]
|
||||
Array.zip u[0, *, 0] v[0, *, 0]
|
||||
|> Array.collect (fun (x, y) -> [| x; y |])
|
||||
with
|
||||
| err ->
|
||||
let u = ds["u"].GetData ([| t; 0; e |], [| 1; l; 1 |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; 0; e |], [| 1; l; 1 |]) :?> single[,,]
|
||||
Array.zip u[0, *, 0] v[0, *, 0] |> Array.collect (fun (x, y) -> [| x; y |])
|
||||
with err ->
|
||||
Log.Warning $"readUv' {e} {t}"
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
@@ -172,10 +500,9 @@ module Siglay =
|
||||
let readTemp (ds: DataSet) n t =
|
||||
try
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let t = ds[ "temp" ].GetData([| t; 0; n |], [| 1; l; 1 |]) :?> single [,,]
|
||||
let t = ds["temp"].GetData ([| t; 0; n |], [| 1; l; 1 |]) :?> single[,,]
|
||||
t[0, *, 0]
|
||||
with
|
||||
| err ->
|
||||
with err ->
|
||||
Log.Warning $"readTemp {n} {t}"
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
@@ -183,50 +510,95 @@ module Siglay =
|
||||
let readSalinity (ds: DataSet) n t =
|
||||
try
|
||||
let l = ds.Dimensions["siglay"].Length
|
||||
let t =
|
||||
ds["salinity"]
|
||||
.GetData([| t; 0; n |], [| 1; l; 1 |])
|
||||
:?> single [,,]
|
||||
let t = ds["salinity"].GetData ([| t; 0; n |], [| 1; l; 1 |]) :?> single[,,]
|
||||
t[0, *, 0]
|
||||
with
|
||||
| err ->
|
||||
with err ->
|
||||
Log.Warning $"readS {n} {t}"
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
|
||||
module Singular =
|
||||
let readUv (ds: DataSet) e t d =
|
||||
try
|
||||
let u = ds["u"].GetData ([| t; d; e |], [| 1; 1; 1 |]) :?> single[,,]
|
||||
let v = ds["v"].GetData ([| t; d; e |], [| 1; 1; 1 |]) :?> single[,,]
|
||||
u[0, 0, 0], v[0, 0, 0]
|
||||
with err ->
|
||||
Log.Warning $"readUv {e} {t}"
|
||||
Log.Error $"{err}"
|
||||
0f, 0f
|
||||
|
||||
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]
|
||||
with err ->
|
||||
Log.Warning $"readTemp {n} {t}"
|
||||
Log.Error $"{err}"
|
||||
0f
|
||||
|
||||
let readSalinity (ds: DataSet) n t d =
|
||||
try
|
||||
let t = ds["salinity"].GetData ([| t; d; n |], [| 1; 1; 1 |]) :?> single[,,]
|
||||
t[0, 0, 0]
|
||||
with err ->
|
||||
Log.Warning $"readS {n} {t}"
|
||||
Log.Error $"{err}"
|
||||
0f
|
||||
|
||||
let readZeta (ds: DataSet) n t =
|
||||
try
|
||||
let zeta = ds["zeta"].GetData ([| t; n |], [| 1; 1 |]) :?> single[,]
|
||||
zeta[0, 0]
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
0f
|
||||
|
||||
let getBBox (ds: DataSet) : BBox =
|
||||
try
|
||||
let x = ds[ "x" ].GetData() :?> single []
|
||||
let y = ds[ "y" ].GetData() :?> single []
|
||||
let x = ds["x"].GetData () :?> single[]
|
||||
let y = ds["y"].GetData () :?> single[]
|
||||
let minX = Array.min x
|
||||
let maxX = Array.max x
|
||||
let minY = Array.min y
|
||||
let maxY = Array.max y
|
||||
let center = minX + (maxX - minX) / 2f, minY + (maxY - minY) / 2f
|
||||
let center = float (minX + maxX) / 2., float (minY + maxY) / 2.
|
||||
{
|
||||
minX = minX
|
||||
maxX = maxX
|
||||
minY = minY
|
||||
maxY = maxY
|
||||
minX = float minX
|
||||
maxX = float maxX
|
||||
minY = float minY
|
||||
maxY = float maxY
|
||||
center = center
|
||||
}
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
BBox.Default
|
||||
BBox.empty
|
||||
|
||||
let getGrid (ds: DataSet) : Grid =
|
||||
let getGrid (ds: DataSet) : FvcomGrid =
|
||||
try
|
||||
let x = ds[ "x" ].GetData() :?> single []
|
||||
let y = ds[ "y" ].GetData() :?> single []
|
||||
let xc = ds[ "xc" ].GetData() :?> single []
|
||||
let yc = ds[ "yc" ].GetData() :?> single []
|
||||
let nv = ds[ "nv" ].GetData() :?> int [,]
|
||||
let x = ds["x"].GetData () :?> single[] |> Array.map float
|
||||
let y = ds["y"].GetData () :?> single[] |> Array.map float
|
||||
let xc = ds["xc"].GetData () :?> single[] |> Array.map float
|
||||
let yc = ds["yc"].GetData () :?> single[] |> Array.map float
|
||||
let nv = ds["nv"].GetData () :?> int[,]
|
||||
|
||||
let h = readBathymetry ds
|
||||
let siglay = Siglay.readSiglay ds
|
||||
let siglay_c = Siglay.readSiglayAtCenter ds
|
||||
let siglev = ds[ "siglev" ].GetData() :?> single [,]
|
||||
let h =
|
||||
match tryReadBathymetry ds with
|
||||
| Some b -> b
|
||||
| None -> Array.empty
|
||||
let siglay =
|
||||
match Siglay.tryReadSiglay ds with
|
||||
| Some s -> s
|
||||
| None -> Array2D.zeroCreate 0 0
|
||||
let siglay_c =
|
||||
match Siglay.tryReadSiglayAtCenter ds with
|
||||
| Some s -> s
|
||||
| None -> Array2D.zeroCreate 0 0
|
||||
let siglev =
|
||||
if ds.Variables.Contains "siglev" then
|
||||
ds["siglev"].GetData () :?> single[,]
|
||||
else
|
||||
Array2D.zeroCreate 0 0
|
||||
let elem =
|
||||
Array.zip3 nv[0, *] nv[1, *] nv[2, *]
|
||||
|> Array.map (fun (a, b, c) -> a - 1, b - 1, c - 1)
|
||||
@@ -242,21 +614,64 @@ let getGrid (ds: DataSet) : Grid =
|
||||
SiglayCenter = siglay_c
|
||||
Siglev = siglev
|
||||
}
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
Grid.Default
|
||||
FvcomGrid.empty
|
||||
|
||||
let writeFvcomRestart (fvcom: DataSet) (data: FvcomRestart) =
|
||||
let getGridLonLat (ds: DataSet) : FvcomGrid =
|
||||
try
|
||||
fvcom
|
||||
.Variables[ "salinity" ]
|
||||
.PutData data.salinity
|
||||
fvcom.Variables[ "temp" ].PutData data.temp
|
||||
fvcom.Variables[ "zeta" ].PutData data.zeta
|
||||
fvcom.Variables[ "u" ].PutData(data.u)
|
||||
fvcom.Variables[ "v" ].PutData(data.v)
|
||||
fvcom.Variables[ "ua" ].PutData(data.ua)
|
||||
fvcom.Variables[ "va" ].PutData(data.va)
|
||||
with
|
||||
| e -> Log.Fatal e.Message
|
||||
let x = ds["lon"].GetData () :?> single[] |> Array.map float
|
||||
let y = ds["lat"].GetData () :?> single[] |> Array.map float
|
||||
let xc = ds["lonc"].GetData () :?> single[] |> Array.map float
|
||||
let yc = ds["latc"].GetData () :?> single[] |> Array.map float
|
||||
let nv = ds["nv"].GetData () :?> int[,]
|
||||
|
||||
let h =
|
||||
match tryReadBathymetry ds with
|
||||
| Some b -> b
|
||||
| None -> Array.empty
|
||||
let siglay =
|
||||
match Siglay.tryReadSiglay ds with
|
||||
| Some s -> s
|
||||
| None -> Array2D.zeroCreate 0 0
|
||||
let siglay_c =
|
||||
match Siglay.tryReadSiglayAtCenter ds with
|
||||
| Some s -> s
|
||||
| None -> Array2D.zeroCreate 0 0
|
||||
let siglev =
|
||||
if ds.Variables.Contains "siglev" then
|
||||
ds["siglev"].GetData () :?> single[,]
|
||||
else
|
||||
Array2D.zeroCreate 0 0
|
||||
let elem =
|
||||
Array.zip3 nv[0, *] nv[1, *] nv[2, *]
|
||||
|> Array.map (fun (a, b, c) -> a - 1, b - 1, c - 1)
|
||||
let nds = Array.zip x y
|
||||
let cells = Array.zip xc yc
|
||||
{
|
||||
Elem = elem
|
||||
Nodes = nds
|
||||
BBox = getBBox ds
|
||||
Cells = cells
|
||||
Bathymetry = h
|
||||
Siglay = siglay
|
||||
SiglayCenter = siglay_c
|
||||
Siglev = siglev
|
||||
}
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
FvcomGrid.empty
|
||||
|
||||
let getNbve (ds: DataSet) =
|
||||
let nbve = ds["nbve"].GetData () :?> int[,]
|
||||
[|
|
||||
for i = 0 to (Array2D.length2 nbve - 1) do
|
||||
nbve[*, i] |> Array.filter ((<>) 0) |> Array.map (fun x -> x - 1) |> Array.rev
|
||||
|]
|
||||
|
||||
let projectFvcomGrid proj (grid: FvcomGrid) : FvcomGrid = {
|
||||
grid with
|
||||
Nodes = grid.Nodes |> Array.Parallel.map proj
|
||||
BBox = projectBBox proj grid.BBox
|
||||
Cells = grid.Cells |> Array.Parallel.map proj
|
||||
}
|
||||
731
src/Grid.fs
731
src/Grid.fs
@@ -3,83 +3,106 @@ module Oceanbox.FvcomKit.Grid
|
||||
open System
|
||||
open FSharpPlus
|
||||
open FSharpPlus.Control
|
||||
open ProjNet.CoordinateSystems
|
||||
open Serilog
|
||||
open ProjNet.FSharp
|
||||
open MessagePack
|
||||
open MBrace.FsPickler
|
||||
//open FsKDTree
|
||||
open KdTree // NOTE: C# version
|
||||
|
||||
open Types
|
||||
|
||||
type NodeIdx = int
|
||||
type ElemIdx = int
|
||||
type Edge = int * int
|
||||
|
||||
type Elem = NodeIdx * NodeIdx * NodeIdx
|
||||
type Node = single * single
|
||||
type Node = float * float
|
||||
|
||||
type BBox =
|
||||
{
|
||||
minX: single
|
||||
maxX: single
|
||||
minY: single
|
||||
maxY: single
|
||||
center: single * single
|
||||
}
|
||||
static member Default =
|
||||
{
|
||||
minX = Single.MaxValue
|
||||
maxX = Single.MinValue
|
||||
minY = Single.MaxValue
|
||||
maxY = Single.MinValue
|
||||
center = 0f, 0f
|
||||
}
|
||||
type Pos = float * float
|
||||
type Leaf<'a> = { Pos: Pos; Data: 'a }
|
||||
type Field = (float * float) array
|
||||
|
||||
type Grid =
|
||||
{
|
||||
Elem: Elem array
|
||||
Nodes: Node array
|
||||
BBox: BBox
|
||||
Cells: Node array
|
||||
Bathymetry: single []
|
||||
Siglay: single [,]
|
||||
SiglayCenter: single [,]
|
||||
Siglev: single [,]
|
||||
}
|
||||
static member Default =
|
||||
{
|
||||
Elem = Array.empty
|
||||
Nodes = Array.empty
|
||||
BBox = BBox.Default
|
||||
Cells = Array.empty
|
||||
Bathymetry = Array.empty
|
||||
Siglay = Array2D.zeroCreate 0 0
|
||||
SiglayCenter = Array2D.zeroCreate 0 0
|
||||
Siglev = Array2D.zeroCreate 0 0
|
||||
}
|
||||
type Cell = NodeIdx * NodeIdx * NodeIdx
|
||||
|
||||
type ElemsAroundNode = Map<NodeIdx, ElemIdx []>
|
||||
type NodesAroundNode = Map<NodeIdx, NodeIdx []>
|
||||
type IGrid =
|
||||
abstract getVertex: int -> Vertex
|
||||
abstract getCell: int -> Cell
|
||||
abstract getCellVertices: int -> Vertex * Vertex * Vertex
|
||||
abstract getVertices: unit -> Vertex array
|
||||
abstract getCells: unit -> Cell array
|
||||
abstract getBoundingBox: unit -> 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]
|
||||
member this.getCellVertices n =
|
||||
let a, b, c = this.Elem[n]
|
||||
this.Nodes[a], this.Nodes[b], this.Nodes[c]
|
||||
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 }
|
||||
|
||||
type ElemsAroundNode = Map<NodeIdx, ElemIdx array>
|
||||
type NodesAroundNode = Map<NodeIdx, NodeIdx array>
|
||||
type ElemsAroundElem = Map<ElemIdx, ElemIdx array>
|
||||
|
||||
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> 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
|
||||
do tree.Balance ()
|
||||
else
|
||||
do Log.Warning $"Empty kd-tree"
|
||||
|
||||
tree
|
||||
|
||||
type private Ean = Map<NodeIdx, ElemIdx array>
|
||||
|
||||
type IndexedFvcomGrid =
|
||||
{
|
||||
Grid: Grid
|
||||
ElemsAroundNode: ElemsAroundNode
|
||||
NodesAroundNode: NodesAroundNode
|
||||
}
|
||||
static member Default =
|
||||
{
|
||||
Grid = Grid.Default
|
||||
ElemsAroundNode = Map.empty
|
||||
NodesAroundNode = Map.empty
|
||||
}
|
||||
let private makeElemsSurroundingNodeMap (elem: Elem array) : ElemsAroundNode =
|
||||
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
|
||||
|
||||
let private makeElemsSurroundingNodeMap' (elem: Elem array) : ElemsAroundNode =
|
||||
let addElemIdx k v nodes =
|
||||
match Map.tryFind k nodes with
|
||||
| Some xs -> Set.add v xs
|
||||
| None -> v |> Set.singleton
|
||||
| None -> Set.singleton v
|
||||
|> fun el -> Map.add k el nodes
|
||||
elem
|
||||
|> Array.fold
|
||||
(fun (n, a) elm ->
|
||||
let x, y, z = elm
|
||||
n + 1,
|
||||
addElemIdx x n a
|
||||
|> addElemIdx y n
|
||||
|> addElemIdx z n)
|
||||
(fun (n, acc) (a, b, c) ->
|
||||
let acc' = acc |> addElemIdx a n |> addElemIdx b n |> addElemIdx c n
|
||||
n + 1, acc'
|
||||
)
|
||||
(0, Map.empty)
|
||||
|> snd
|
||||
|> Map.mapValues toArray
|
||||
@@ -90,38 +113,51 @@ 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 private 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
|
||||
|
||||
let makeIndexedGrid grid =
|
||||
Log.Information "Indexing grids."
|
||||
let ean = makeElemsSurroundingNodeMap grid.Elem
|
||||
{
|
||||
Grid = grid
|
||||
ElemsAroundNode = ean
|
||||
NodesAroundNode = makeNodesSurroudingNodeMap ean grid.Elem
|
||||
NodesAroundNode = makeNodesSurroudingNodeMap ean elem
|
||||
ElemsAroundElem = makeElemsSurroundingElemMap ean elem
|
||||
}
|
||||
|> fun x ->
|
||||
Log.Debug "...done indexing grids."
|
||||
x
|
||||
|
||||
let getElemsSurroundingNode (iGrid: IndexedFvcomGrid) n = iGrid.ElemsAroundNode[n]
|
||||
let getElemsSurroundingNode (idx: NeighborIndex) n = idx.ElemsAroundNode[n]
|
||||
|
||||
let getNodesSurroundingNode (iGrid: IndexedFvcomGrid) n = iGrid.NodesAroundNode[n]
|
||||
let getNodesSurroundingNode (idx: NeighborIndex) n = idx.NodesAroundNode[n]
|
||||
|
||||
let getNodesSurroundingElem (iGrid: IndexedFvcomGrid) e =
|
||||
getSurrounding iGrid.NodesAroundNode (iGrid.Grid.Elem[e])
|
||||
let getNodesSurroundingElem (idx: NeighborIndex) e = idx.ElemsAroundElem[e]
|
||||
|
||||
let getElemsSurroundingElem (iGrid: IndexedFvcomGrid) e =
|
||||
getSurrounding iGrid.ElemsAroundNode (iGrid.Grid.Elem[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]
|
||||
|
||||
let calcBBoxCenter (x: BBox) =
|
||||
x.minX + (x.maxX - x.minX) / 2.0f, x.minY + (x.maxY - x.minY) / 2.0f
|
||||
x.minX + (x.maxX - x.minX) / 2.0, x.minY + (x.maxY - x.minY) / 2.0
|
||||
|
||||
let calcBBox nodes =
|
||||
let x, y = Array.unzip nodes
|
||||
@@ -130,14 +166,14 @@ let calcBBox nodes =
|
||||
maxX = Array.max x
|
||||
minY = Array.min y
|
||||
maxY = Array.max y
|
||||
center = 0f, 0f
|
||||
center = 0, 0
|
||||
}
|
||||
|> fun x -> { x with center = calcBBoxCenter x }
|
||||
|
||||
let printBBox grid = calcBBox grid.Nodes |> printfn "%A"
|
||||
|
||||
let bboxToLngLat b =
|
||||
let toLatLon = ProjNet.FSharp.UTM_TO_WGS84 33
|
||||
let bboxToLngLat (coordsys: CoordinateSystem) b =
|
||||
let toLatLon = makeTransform coordsys CoordSys.WGS84
|
||||
let x0, y0 = toLatLon.project ((b.minX, b.minY))
|
||||
let x1, y1 = toLatLon.project ((b.maxX, b.maxY))
|
||||
// Log.Error (sprintf "(%f, %f) (%f, %f)" x0 y0 x1 y1)
|
||||
@@ -152,92 +188,543 @@ let bboxToLngLat 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 }
|
||||
|
||||
let projectGrid proj (grid: Grid) : Grid =
|
||||
{ grid with
|
||||
Nodes = grid.Nodes |> Array.Parallel.map proj
|
||||
BBox = projectBBox proj grid.BBox
|
||||
Cells = grid.Cells |> Array.Parallel.map proj
|
||||
{
|
||||
minX = x0
|
||||
maxX = x1
|
||||
minY = y0
|
||||
maxY = y1
|
||||
center = proj b.center
|
||||
}
|
||||
|
||||
let toWebMercator (grid: Grid) =
|
||||
let toWebMercator = ProjNet.FSharp.UTM_TO_EPSG3857 33
|
||||
let s = System.Diagnostics.Stopwatch.StartNew()
|
||||
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' }
|
||||
|
||||
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' }
|
||||
|
||||
let toWebMercator (coordsys: CoordinateSystem) (grid: Grid) =
|
||||
let toWebMercator = makeTransform coordsys CoordSys.EPSG3857
|
||||
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
|
||||
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
|
||||
|
||||
let private readElem (f: string array) =
|
||||
let p =
|
||||
function
|
||||
| [| _; a; b; c; _ |] -> int a - 1, int b - 1, int c - 1
|
||||
| [| a; b; c |] -> int a - 1, int b - 1, int c - 1
|
||||
| _ -> failwith "readElem failed"
|
||||
| [| _; a; b; c; _ |] -> int a - 1, int b - 1, int c - 1
|
||||
| [| a; b; c |] -> int a - 1, int b - 1, int c - 1
|
||||
| _ -> failwith "readElem failed"
|
||||
reader p f
|
||||
|
||||
let private readNodes (f: string array) =
|
||||
let p =
|
||||
function
|
||||
| [| _; x; y; _ |] -> single x, single y
|
||||
| [| x; y |] -> single x, single y
|
||||
| x -> failwith $"readNodes failed: %A{x}"
|
||||
| [| _; x; y; _ |] -> float x, float y
|
||||
| [| x; y |] -> float x, float y
|
||||
| x -> failwith $"readNodes failed: %A{x}"
|
||||
reader p f
|
||||
|
||||
let private readObc (f: string array) =
|
||||
let p =
|
||||
function
|
||||
| [| _; x; _ |] -> int x
|
||||
| [| x; _ |] -> int x
|
||||
| [| x |] -> int x
|
||||
| _ -> failwith "readObc failed"
|
||||
| [| _; x; _ |] -> int x - 1
|
||||
| [| x; _ |] -> int x - 1
|
||||
| [| x |] -> int x - 1
|
||||
| _ -> failwith "readObc failed"
|
||||
reader p f
|
||||
|
||||
let readGrdFile (filename: string) =
|
||||
let f = System.IO.File.ReadAllLines filename
|
||||
let hdr, rest = Array.splitAt 2 f
|
||||
readGrdHeader hdr
|
||||
|> Option.bind (fun (nnds, nele) ->
|
||||
|> Option.bind (fun (_, nele) ->
|
||||
let els, nds = Array.splitAt nele rest
|
||||
let elem = readElem els
|
||||
let nodes = readNodes nds
|
||||
let toGrid e n =
|
||||
{
|
||||
Grid.Default with
|
||||
Elem = e
|
||||
Nodes = n
|
||||
BBox = calcBBox n
|
||||
}
|
||||
let nodes = readNodes nds
|
||||
let toGrid e n = { Elem = e; Nodes = n; BBox = calcBBox n }
|
||||
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) =
|
||||
[| a; b; c |]
|
||||
|> Array.sort
|
||||
|> fun x -> [| x[0], x[1]; x[1], x[2]; x[0], x[2] |]
|
||||
|
||||
let makeBoundaryByEdgeMap (grid: Grid) : Map<Edge, ElemIdx> =
|
||||
let normElIdx n e = n, normalizeElement e
|
||||
let appendEdge (n, edge: Edge) a =
|
||||
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])
|
||||
grid.Elem
|
||||
|> Array.mapi normElIdx
|
||||
|> Array.fold appendEdges Map.empty
|
||||
|> Map.filter (fun _ v -> v.Length = 1)
|
||||
|> Map.mapValues List.head
|
||||
|
||||
let makeBoundaryByNodeMap (edges: Map<Edge, ElemIdx>) : Map<NodeIdx, ElemIdx * ElemIdx> =
|
||||
let add node elem a =
|
||||
match Map.tryFind node a with
|
||||
| Some v -> Map.add node (elem :: v) a
|
||||
| None -> Map.add node [ elem ] a
|
||||
let appendNodes a (n1, n2) e = a |> add n1 e |> add n2 e
|
||||
edges
|
||||
|> Map.fold appendNodes Map.empty
|
||||
|> 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
|
||||
|
||||
let getBoundaryNodesArray (edgeMap: Map<Edge, ElemIdx>) =
|
||||
edgeMap
|
||||
|> Map.keys
|
||||
|> Array.ofSeq
|
||||
|> Array.collect (fun (a, b) -> [| a; b |])
|
||||
|> Array.distinct
|
||||
|
||||
module Util =
|
||||
// let private floatify = bimap float float
|
||||
|
||||
type Element =
|
||||
static member calcCentroid((x0, y0), (x1, y1), (x2, y2)) =
|
||||
(x0 + x1 + x2) / 3.0, (y0 + y1 + y2) / 3.0
|
||||
|
||||
static member calcCentroid((x0, y0), (x1, y1), (x2, y2)) =
|
||||
(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
|
||||
|
||||
// static member calcArea((x0, y0), (x1, y1), (x2, y2)) =
|
||||
// x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)
|
||||
// |> (*) 0.5f
|
||||
|
||||
static member calcCircumscribedCircle((Ax, Ay as A), (Bx, By as B), (Cx, Cy as C)) =
|
||||
let square (i, j) = i * i + j * j
|
||||
let det (i0, i1, i2) (j0, j1, j2) (k0, k1, k2) =
|
||||
i0 * (j1 * k2 - k1 * j2) - j0 * (i1 * k2 - k1 * i2) + k0 * (i1 * j2 - j1 * i2)
|
||||
let T2 = square A, square B, square C
|
||||
let Tx = Ax, Bx, Cx
|
||||
let Ty = Ay, By, Cy
|
||||
let E = 1.0, 1.0, 1.0
|
||||
let Sx = det T2 Ty E |> (*) 0.5
|
||||
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"
|
||||
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[]) =
|
||||
[| 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)
|
||||
)
|
||||
|
||||
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]
|
||||
ns
|
||||
|> Array.fold
|
||||
(fun a n ->
|
||||
let u, v = s[n]
|
||||
sqrt (u * u + v * v) + a
|
||||
)
|
||||
0.
|
||||
|> (*) (1. / float ns.Length)
|
||||
)
|
||||
|
||||
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]
|
||||
let n = float ns.Length
|
||||
ns
|
||||
|> Array.fold
|
||||
(fun (au, av) n ->
|
||||
let u, v = s[n]
|
||||
u + au, v + av
|
||||
)
|
||||
(0., 0.)
|
||||
|> fun (u, v) -> u / n, v / n
|
||||
)
|
||||
|
||||
type Node =
|
||||
static member calcNodeControlArea (idx: NeighborIndex) (grid: IGrid) =
|
||||
let half = (*) 0.5
|
||||
let nodes = grid.getVertices ()
|
||||
[| 0 .. nodes.Length - 1 |]
|
||||
|> Array.Parallel.map (fun n ->
|
||||
getElemsSurroundingNode idx n
|
||||
|> Array.map (fun e ->
|
||||
let p0, p1, p2 = grid.getCellVertices e
|
||||
let x0, y0 as p0' = p0
|
||||
let x1, y1 = p1
|
||||
let x2, y2 = p2
|
||||
let p1' = x0 + half (x1 - x0), y0 + half (y1 - y0)
|
||||
let p2' = x0 + half (x2 - x0), y0 + half (y2 - y0)
|
||||
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
|
||||
)
|
||||
|
||||
static member calcNodeArea (idx: NeighborIndex) (grid: IGrid) =
|
||||
let nodes = grid.getVertices ()
|
||||
[| 0 .. nodes.Length - 1 |]
|
||||
|> Array.Parallel.map (fun n ->
|
||||
getElemsSurroundingNode idx n
|
||||
|> Array.map (grid.getCellVertices >> Element.calcArea)
|
||||
|> Array.sum
|
||||
)
|
||||
|
||||
let calcCentroids (grid: IGrid) =
|
||||
let n = grid.getVertices ()
|
||||
grid.getCells ()
|
||||
|> Array.Parallel.map (fun (a, b, c) ->
|
||||
let p0 = n[a]
|
||||
let p1 = n[b]
|
||||
let p2 = n[c]
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
// make a kd-tree for looking up nearest node
|
||||
let buildNearestNodeTree (grid: IGrid) =
|
||||
grid.getVertices ()
|
||||
|> Array.mapi (fun i v ->
|
||||
let x, y = v
|
||||
{ Pos = x, y; Data = i }
|
||||
)
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createTree
|
||||
|
||||
// make a kd-tree for looking up nearest element
|
||||
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 }
|
||||
)
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createTree
|
||||
|
||||
// let tryFindElement
|
||||
// (grid: IGrid)
|
||||
// (tree: Tree<Leaf<single, ElemIdx> array, Node<single>>)
|
||||
// ((p0, p1): single * single) =
|
||||
// nearestNeighbor tree { X = p0; Y = p1 }
|
||||
// |> Option.bind (fun leaf ->
|
||||
// let vx = grid.getCellVertices leaf.Data
|
||||
// if isInsideTriangle vx (p0, p1)
|
||||
// then Some leaf.Data
|
||||
// else None)
|
||||
|
||||
let tryFindElement (grid: IGrid) (tree: KdTree<float, int>) ((p0, p1): float * float) =
|
||||
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
|
||||
)
|
||||
|
||||
// type private IdxTree = Tree<Leaf<single, ElemIdx> array, Node<single>>
|
||||
// type private NodeIdxTree = Tree<Leaf<single, NodeIdx> array, Node<single>>
|
||||
type private IdxTree = KdTree<float, int>
|
||||
type private NodeIdxTree = KdTree<float, int>
|
||||
|
||||
[<MessagePackObject>]
|
||||
type BinGrid = {
|
||||
[<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 }
|
||||
|
||||
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 gridHash: byte[] = [||]
|
||||
|
||||
let getNeighborIdx () =
|
||||
match neighborIndex with
|
||||
| Some idx -> idx
|
||||
| None ->
|
||||
neighborIndex <- makeNeighborIndex grid |> Some
|
||||
neighborIndex.Value
|
||||
|
||||
interface IGrid with
|
||||
member this.getVertex n = grid.getVertex n
|
||||
member this.getCell n = grid.getCell n
|
||||
member this.getCellVertices n = grid.getCellVertices n
|
||||
member this.getVertices() = grid.getVertices ()
|
||||
member this.getCells() = grid.getCells ()
|
||||
member this.getBoundingBox() = grid.getBoundingBox ()
|
||||
|
||||
member this.NeighborIndex = neighborIndex
|
||||
member this.NodeTree = nodeTree
|
||||
member this.ElementTree = elementTree
|
||||
|
||||
member this.Grid = grid
|
||||
|
||||
member this.ToGrid() = {
|
||||
Nodes = this.Grid.getVertices ()
|
||||
Elem = this.Grid.getCells ()
|
||||
BBox = this.Grid.getBoundingBox ()
|
||||
}
|
||||
|
||||
|
||||
member this.initNeighborIndex(?cache: string) =
|
||||
match neighborIndex with
|
||||
| Some _ -> ()
|
||||
| None -> neighborIndex <- makeNeighborIndex grid |> Some
|
||||
|
||||
member this.initNodeTree() =
|
||||
match nodeTree with
|
||||
| Some _ -> ()
|
||||
| None -> nodeTree <- Util.buildNearestNodeTree grid |> Some
|
||||
|
||||
member this.initElementTree() =
|
||||
match elementTree with
|
||||
| Some _ -> ()
|
||||
| None -> elementTree <- Util.buildNearestElementTree grid |> Some
|
||||
|
||||
member this.nearestNode(p0: float, p1: float) =
|
||||
let nearest (tree: KdTree<_, _>) =
|
||||
tree.GetNearestNeighbours ([| p0; p1 |], 1)
|
||||
|> Array.tryHead
|
||||
|> Option.map (fun l -> l.Value)
|
||||
match nodeTree with
|
||||
| Some tree -> nearest tree
|
||||
| None ->
|
||||
this.initNodeTree ()
|
||||
nearest nodeTree.Value
|
||||
|
||||
member this.tryGetNode(p: float * float) =
|
||||
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
|
||||
)
|
||||
|
||||
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)
|
||||
|> Array.tryHead
|
||||
|> Option.bind (fun leaf ->
|
||||
this.getElemsSurroundingElem leaf.Value
|
||||
|> Array.tryFind (fun eIdx ->
|
||||
let vx = this.Grid.getCellVertices eIdx
|
||||
Util.isInsideTriangle vx p
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
member this.tryGetElement p =
|
||||
elementTree
|
||||
|> Option.bind (fun tree -> this.tryFindElementTwice grid tree p)
|
||||
|> Option.orElseWith (fun () ->
|
||||
this.initElementTree ()
|
||||
this.tryFindElementTwice grid elementTree.Value p
|
||||
)
|
||||
|
||||
member this.tryGetElementSloppy(p0, p1 as p) =
|
||||
match elementTree with
|
||||
| Some tree -> Util.tryFindElement grid tree p
|
||||
| None ->
|
||||
this.initElementTree ()
|
||||
// this.initNodeTree ()
|
||||
Util.tryFindElement grid elementTree.Value p
|
||||
|
||||
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 ()
|
||||
gridHash <- sha1.ComputeHash bytes
|
||||
gridHash
|
||||
|
||||
member this.getHashString() =
|
||||
this.getHash () |> Convert.ToHexStringLower
|
||||
|
||||
member this.getCentroids() =
|
||||
match centroids with
|
||||
| Some cx -> cx
|
||||
| None ->
|
||||
let cx = Util.calcCentroids grid
|
||||
centroids <- Some cx
|
||||
cx
|
||||
|
||||
member this.calcCircumCircle e =
|
||||
let triangle = grid.getCellVertices e
|
||||
Util.Element.calcCircumscribedCircle triangle
|
||||
|
||||
member this.getElemsSurroundingNode n =
|
||||
getNeighborIdx () |> fun idx -> idx.ElemsAroundNode[n]
|
||||
|
||||
member this.getNodesSurroundingNode n =
|
||||
getNeighborIdx () |> fun idx -> idx.NodesAroundNode[n]
|
||||
|
||||
member this.getNodesSurroundingElem e =
|
||||
let idx = getNeighborIdx ()
|
||||
let elem = grid.getCell e
|
||||
getSurrounding idx.NodesAroundNode elem
|
||||
|
||||
member this.getElemsSurroundingElem e =
|
||||
let idx = getNeighborIdx ()
|
||||
let elem = grid.getCell e
|
||||
getSurrounding idx.ElemsAroundNode elem
|
||||
|
||||
member this.saveNeighborIndex(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let nix = getNeighborIdx ()
|
||||
let pickle = binarySerializer.Pickle nix
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member this.loadNeighborIndex(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
if IO.File.Exists fname then
|
||||
let pickle = IO.File.ReadAllBytes fname
|
||||
neighborIndex <- binarySerializer.UnPickle<NeighborIndex> pickle |> Some
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
member this.saveNodeTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let tree =
|
||||
nodeTree
|
||||
|> Option.defaultWith (fun () ->
|
||||
this.initNodeTree ()
|
||||
nodeTree.Value
|
||||
)
|
||||
|
||||
let pickle = binarySerializer.Pickle tree
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member this.loadNodeTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
if IO.File.Exists fname then
|
||||
let pickle = IO.File.ReadAllBytes fname
|
||||
nodeTree <- binarySerializer.UnPickle<IdxTree> pickle |> Some
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
member this.saveElementTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let tree =
|
||||
elementTree
|
||||
|> Option.defaultWith (fun () ->
|
||||
this.initElementTree ()
|
||||
elementTree.Value
|
||||
)
|
||||
|
||||
let pickle = binarySerializer.Pickle tree
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member this.loadElementTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
if IO.File.Exists fname then
|
||||
let pickle = IO.File.ReadAllBytes fname
|
||||
elementTree <- binarySerializer.UnPickle<IdxTree> pickle |> Some
|
||||
true
|
||||
else
|
||||
false
|
||||
236
src/Interpol.fs
236
src/Interpol.fs
@@ -1,17 +1,15 @@
|
||||
module Oceanbox.FvcomKit.Interpol
|
||||
|
||||
open MathNet.Numerics.LinearAlgebra
|
||||
open Serilog
|
||||
open Types
|
||||
open ROMS
|
||||
open Grid
|
||||
open Oceanbox.FvcomKit.Grid
|
||||
open Adjoin
|
||||
|
||||
type InterpolCoefs = ((int * int) * (float * float)) array array
|
||||
|
||||
type DepthInterpolCoefs = { iRho: InterpolCoefs; iU: InterpolCoefs; iV: InterpolCoefs }
|
||||
|
||||
let private findNearestZ z0 (h: float []) =
|
||||
let rec findNerest' z0 (h: float []) d n =
|
||||
let private findNearestZ z0 (h: float[]) =
|
||||
let rec findNerest' z0 (h: float[]) d n =
|
||||
if n < h.Length - 1 then
|
||||
let d' = abs (h[n] - z0)
|
||||
if d' < d then findNerest' z0 h d' (n + 1) else n
|
||||
@@ -23,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)
|
||||
@@ -42,101 +41,170 @@ let private calcInterpolationWeightedIdx (rn, fn) =
|
||||
else
|
||||
failwith "not reachable")
|
||||
|
||||
let private calcInterpMatrices (rz: float [] []) (fz: float [] []) =
|
||||
Array.zip rz fz
|
||||
|> Array.Parallel.map calcInterpolationWeightedIdx
|
||||
let private calcInterpMatrices (rz: float[][]) (fz: float[][]) =
|
||||
Array.zip rz fz |> Array.Parallel.map calcInterpolationWeightedIdx
|
||||
|
||||
let mkDepthInterpolCoefs (siglay: single [,]) (h: float []) (roms: float [] []) =
|
||||
let s =
|
||||
siglay
|
||||
|> Array2D.map float
|
||||
|> Matrix.Build.DenseOfArray
|
||||
let mkDepthInterpolCoefs (siglay: single[,]) (h: float[]) (roms: float[][]) =
|
||||
let s = siglay |> Array2D.map float |> Matrix.Build.DenseOfArray
|
||||
let rescale (sigma: float Matrix) h =
|
||||
let sh = h |> Array.map float
|
||||
sigma.MapIndexed(fun _ j x -> -x * sh[j])
|
||||
|> fun x -> x.ToColumnArrays()
|
||||
sigma.MapIndexed (fun _ j x -> -x * sh[j]) |> fun x -> x.ToColumnArrays ()
|
||||
|
||||
let conv m =
|
||||
m
|
||||
|> Array.map (Array.map ((*) -1.0))
|
||||
|> matrix
|
||||
|> fun x -> x.ToColumnArrays()
|
||||
|> fun x -> x.ToColumnArrays ()
|
||||
|
||||
let romz = conv roms
|
||||
let z = rescale s h
|
||||
calcInterpMatrices romz z
|
||||
|
||||
// Linear interpolation to nearest vertical neighbor
|
||||
let mkAllDepthInterpolCoefs (fvcom: Grid) (roms: AdjoinedGrid) =
|
||||
Log.Information "Computing interpolation coefficients."
|
||||
let uv =
|
||||
Array.zip roms.u roms.v
|
||||
|> Array.map (fun (u, v) -> (u + v) * 0.5)
|
||||
{
|
||||
iRho = mkDepthInterpolCoefs fvcom.Siglay roms.h roms.zRho
|
||||
iU = mkDepthInterpolCoefs fvcom.SiglayCenter uv roms.zU
|
||||
iV = mkDepthInterpolCoefs fvcom.SiglayCenter uv roms.zV
|
||||
}
|
||||
|
||||
let zInterpolProp (iz: InterpolCoefs) (adjRomsProp: float [] []) =
|
||||
let zInterpolProp (iz: InterpolCoefs) (adjRomsProp: float[][]) =
|
||||
let pz = adjRomsProp |> matrix
|
||||
iz
|
||||
|> Array.Parallel.mapi (fun n x ->
|
||||
let p = pz[ *, n ].ToArray() |> Array.rev
|
||||
x
|
||||
|> Array.map (fun ((i1, i2), (w1, w2)) -> p[i1] * w1 + p[i2] * w2))
|
||||
let p = pz[*, n].ToArray () |> Array.rev
|
||||
x |> Array.map (fun ((i1, i2), (w1, w2)) -> p[i1] * w1 + p[i2] * w2))
|
||||
|> matrix
|
||||
|> fun x -> x.Transpose().ToArray()
|
||||
|> fun x -> x.Transpose().ToArray ()
|
||||
|
||||
// Trivially already satisfied by ajoint
|
||||
let hInterpolNearestProp (adjRomsProp: float [] []) = adjRomsProp
|
||||
let hInterpolNearestProp (adjRomsProp: float[][]) = adjRomsProp
|
||||
|
||||
let interpolateFromRoms doUv fvGrid rGrid rProps =
|
||||
let aGrid, aProps = adjoinRomsToFvcom fvGrid rGrid rProps
|
||||
let ic = mkAllDepthInterpolCoefs fvGrid aGrid
|
||||
Log.Information "Interpolating props."
|
||||
let fvData: Fvcom.FvcomRestart =
|
||||
{
|
||||
salinity = zInterpolProp ic.iRho aProps.salt |> propTo3D
|
||||
temp = zInterpolProp ic.iRho aProps.temp |> propTo3D
|
||||
zeta = aProps.zeta |> propTo2D
|
||||
u = Array3D.zeroCreate 0 0 0
|
||||
v = Array3D.zeroCreate 0 0 0
|
||||
ua = Array2D.zeroCreate 0 0
|
||||
va = Array2D.zeroCreate 0 0
|
||||
}
|
||||
if doUv then
|
||||
Log.Information "Interpolating u and v."
|
||||
let angles =
|
||||
computeAngles fvGrid aGrid
|
||||
|> Vector.Build.DenseOfArray
|
||||
let cosA = Vector.Cos angles
|
||||
let sinA = Vector.Sin angles
|
||||
let u =
|
||||
zInterpolProp ic.iU aProps.u
|
||||
|> Matrix.Build.DenseOfArray
|
||||
let v =
|
||||
zInterpolProp ic.iV aProps.v
|
||||
|> Matrix.Build.DenseOfArray
|
||||
let k =
|
||||
[|
|
||||
for i = 0 to u.RowCount - 1 do
|
||||
let u' = u.Row i
|
||||
let v' = v.Row i
|
||||
u'.PointwiseMultiply cosA
|
||||
- v'.PointwiseMultiply sinA,
|
||||
u'.PointwiseMultiply sinA
|
||||
+ v'.PointwiseMultiply cosA
|
||||
|]
|
||||
Log.Information "Computing ubar and vbar."
|
||||
let u' = k |> Array.map (fun (u, _) -> u.ToArray())
|
||||
let v' = k |> Array.map (fun (_, v) -> v.ToArray())
|
||||
let ubar, vbar = calcUVBar fvGrid (u', v')
|
||||
{ fvData with
|
||||
u = u' |> matrix |> fun x -> x.ToArray() |> propTo3D
|
||||
v = v' |> matrix |> fun x -> x.ToArray() |> propTo3D
|
||||
ua = ubar.ToArray() |> propTo2D
|
||||
va = vbar.ToArray() |> propTo2D
|
||||
}
|
||||
type BiWght = float * float * float * float
|
||||
type BiProp = float * float * float * float
|
||||
type NW'SE = (float * float) * (float * float)
|
||||
|
||||
let genBilinearInterpolationWgts
|
||||
(x: float, y: float)
|
||||
((x0, y0), (x1, y1), (x2, y2), (x3, y3))
|
||||
((mask0, mask1, mask2, mask3): bool * bool * bool * bool)
|
||||
: BiWght option =
|
||||
if mask0 && mask1 && mask2 && mask3 then
|
||||
let AB = (x1 - x0) ** 2.0 + (y1 - y0) ** 2.0 |> sqrt
|
||||
let BC = (x2 - x1) ** 2.0 + (y2 - y1) ** 2.0 |> sqrt
|
||||
let CD = (x3 - x2) ** 2.0 + (y3 - y2) ** 2.0 |> sqrt
|
||||
let DA = (x0 - x3) ** 2.0 + (y0 - y3) ** 2.0 |> sqrt
|
||||
let h0 =
|
||||
let a0 = (x * (y0 - y3) + x0 * (y3 - y) + x3 * (y - y0)) * 0.5
|
||||
2.0 * a0 / DA
|
||||
let h1 =
|
||||
let a1 = (x * (y1 - y0) + x0 * (y - y1) + x1 * (y0 - y)) * 0.5
|
||||
2.0 * a1 / AB
|
||||
let w00 = (h0 / AB - 1.0) * (h1 / DA - 1.0)
|
||||
let w10 = h0 / AB * (1.0 - h1 / DA)
|
||||
let w11 = h1 / DA * h0 / CD
|
||||
let w01 = h1 / DA * (1.0 - h0 / CD)
|
||||
Some (w00, w10, w11, w01)
|
||||
else
|
||||
fvData
|
||||
None
|
||||
|
||||
let makeBiWeights
|
||||
(pos: (float * float)[])
|
||||
(boxes: ((float * float) * (float * float) * (float * float) * (float * float))[])
|
||||
(mask: (bool * bool * bool * bool)[])
|
||||
=
|
||||
Array.zip3 pos boxes mask
|
||||
|> Array.map (fun (p, b, m) -> genBilinearInterpolationWgts p b m)
|
||||
|
||||
let interpolateCells (wghts: BiWght option[]) (prop: BiProp[]) =
|
||||
Array.zip wghts prop
|
||||
|> Array.Parallel.map (fun (w, (p00, p01, p11, p10)) ->
|
||||
match w with
|
||||
| Some w ->
|
||||
let w00, w01, w11, w10 = w
|
||||
Some (w00 * p00 + w01 * p01 + w11 * p11 + w10 * p10)
|
||||
| None -> None)
|
||||
// |> Array.Parallel.map (fun ((w00, w01, w11, w10), (p00, p01, p11, p10)) ->
|
||||
// w00 * p00 + w01 * p01 + w11 * p11 + w10 * p10)
|
||||
|
||||
let private valtest (intval: float option[]) =
|
||||
let somval = intval |> Array.filter (fun v -> Option.isSome v)
|
||||
somval.Length = intval.Length
|
||||
|
||||
let private fillOutOfBounds (grid: Grid) (interpVal: float option[]) =
|
||||
let node = interpVal.Length = grid.Nodes.Length
|
||||
let nbridx = makeNeighborIndex (grid :> IGrid)
|
||||
let mutable allval = valtest interpVal
|
||||
while not allval do
|
||||
for n = 0 to interpVal.Length - 1 do
|
||||
if Option.isNone interpVal[n] then
|
||||
let nb =
|
||||
if node then
|
||||
nbridx.NodesAroundNode[n] |> Array.filter (fun k -> Option.isSome interpVal[k])
|
||||
else
|
||||
getElemsSurroundingElem nbridx grid n
|
||||
|> Array.filter (fun k -> Option.isSome interpVal[k])
|
||||
if nb.Length > 0 then
|
||||
let nval = nb |> Array.map (fun k -> interpVal[k].Value) |> Array.average
|
||||
interpVal[n] <- Some nval
|
||||
allval <- valtest interpVal
|
||||
interpVal |> Array.map (fun v -> v.Value)
|
||||
|
||||
let interpolateProp
|
||||
(coords, _ as grid: BiPos * Mask)
|
||||
(pos: (float * float)[])
|
||||
(prop: float[,])
|
||||
(fvgrid: Grid)
|
||||
(oob: bool)
|
||||
=
|
||||
let cm = getNearestCellCorner grid pos
|
||||
let boxes, mask =
|
||||
cm
|
||||
|> Array.Parallel.map (fun box -> getCellBox coords box)
|
||||
|> Array.map (fun (coord, m) -> (coord[0], coord[1], coord[2], coord[3]), (m[0], m[1], m[2], m[3]))
|
||||
|> Array.unzip
|
||||
let wghts = makeBiWeights pos boxes mask
|
||||
let boxProps =
|
||||
cm
|
||||
|> Array.map (fun box -> box |> Array.map (fun ((n, m), _) -> prop[n, m]))
|
||||
|> Array.map (fun p -> (p[0], p[1], p[2], p[3]))
|
||||
let iprop = interpolateCells wghts boxProps
|
||||
if not (valtest iprop) && (not oob) then
|
||||
let sidx =
|
||||
iprop
|
||||
|> Array.mapi (fun id p ->
|
||||
match p with
|
||||
| Some _ -> -1
|
||||
| None -> id)
|
||||
|> Array.filter (fun i -> i > 0)
|
||||
|> Array.fold (fun a i -> a + "; " + string i) ""
|
||||
failwith ($"FVCOM grid out of bounds. Oob indexes: {sidx}")
|
||||
if oob then
|
||||
fillOutOfBounds fvgrid iprop
|
||||
else
|
||||
iprop |> Array.map (fun v -> v.Value)
|
||||
|
||||
let interpCoefs (coords, _ as grid: BiPos * Mask) (pos: (float * float)[]) =
|
||||
let cm = getNearestCellCorner grid pos
|
||||
let boxes, mask =
|
||||
cm
|
||||
|> Array.Parallel.map (fun box -> getCellBox coords box)
|
||||
|> Array.map (fun (coord, m) -> (coord[0], coord[1], coord[2], coord[3]), (m[0], m[1], m[2], m[3]))
|
||||
|> Array.unzip
|
||||
let wgths = makeBiWeights pos boxes mask
|
||||
let corneridx =
|
||||
cm |> Array.map (fun c -> Array.unzip c) |> Array.map (fun (i, _) -> i)
|
||||
corneridx, wgths
|
||||
|
||||
let interpProp (corneridx: (int * int)[][]) (wgths: BiWght option[]) (prop: float[,]) (grid: Grid) (oob: bool) =
|
||||
let boxProps =
|
||||
corneridx
|
||||
|> Array.map (fun box -> box |> Array.map (fun (n, m) -> prop[n, m]))
|
||||
|> Array.map (fun p -> (p[0], p[1], p[2], p[3]))
|
||||
let iprop = interpolateCells wgths boxProps
|
||||
if not (valtest iprop) && (not oob) then
|
||||
let sidx =
|
||||
iprop
|
||||
|> Array.mapi (fun i p ->
|
||||
match p with
|
||||
| Some _ -> -1
|
||||
| None -> i)
|
||||
|> Array.filter (fun i -> i >= 0)
|
||||
|> Array.fold (fun a i -> a + "; " + string i) ""
|
||||
failwith ($"FVCOM grid out of bounds. Oob indexes: {sidx}")
|
||||
if oob then
|
||||
fillOutOfBounds grid iprop
|
||||
else
|
||||
iprop |> Array.map (fun v -> v.Value)
|
||||
@@ -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 t = t.ToUniversalTime ()
|
||||
let now = DateTime.Now.ToUniversalTime ()
|
||||
let dDay = (now.Date - t.Date).Days
|
||||
|
||||
if dDay < 0 then // no data available
|
||||
[]
|
||||
else
|
||||
@@ -21,6 +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}/norshelf_{kind}_{mode}_{fmt date}"
|
||||
|
||||
$"{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 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,11 +29,10 @@ 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)))
|
||||
|> Option.bind (fun (fname, ds) -> tryGetTimeIndex ds t |> Option.map (fun idx -> (fname, ds, idx)))
|
||||
|
||||
let readArchive file reader =
|
||||
tryOpenArchive file
|
||||
@@ -40,12 +41,11 @@ let readArchive file reader =
|
||||
let data = reader nc
|
||||
Log.Information $"Read NorShelf data from {file}"
|
||||
Some data
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error e.Message
|
||||
None)
|
||||
|
||||
let readRomsGrid fname = readArchive fname readGrid
|
||||
|
||||
let readRomsProps fname idx =
|
||||
readArchive fname ((flip readProps) idx)
|
||||
readArchive fname ((flip readProps) idx)
|
||||
@@ -1,38 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>Oceanbox.FvcomKit</PackageId>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Company>Oceanbox AS</Company>
|
||||
<Authors/>
|
||||
<Company/>
|
||||
<Version>1.1.0</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"/>
|
||||
<Compile Include="Grid.fs"/>
|
||||
<Compile Include="Arome.fs"/>
|
||||
<Compile Include="Fvcom.fs"/>
|
||||
<Compile Include="Thredds.fs"/>
|
||||
<Compile Include="ROMS.fs"/>
|
||||
<Compile Include="Polygon.fs"/>
|
||||
<Compile Include="Adjoin.fs"/>
|
||||
<Compile Include="Interpol.fs"/>
|
||||
<Compile Include="ROMS.fs"/>
|
||||
<Compile Include="NorKyst.fs"/>
|
||||
<Compile Include="NorShelf.fs"/>
|
||||
<Compile Include="Smoothing.fs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="FSharp.Core" Version="6.0.4-beta.22181.2"/>
|
||||
<PackageReference Include="FSharp.Data" Version="4.2.8"/>
|
||||
<PackageReference Include="FSharpPlus" Version="1.2.3.1-PR476-02311"/>
|
||||
<PackageReference Include="FSharp.Data" Version="6.4.1"/>
|
||||
<PackageReference Include="FSharpPlus" Version="1.7.0"/>
|
||||
<PackageReference Include="FsPickler" Version="5.3.2"/>
|
||||
<PackageReference Include="KDTree" Version="1.4.1"/>
|
||||
<PackageReference Include="MathNet.Numerics.FSharp" Version="5.0.0"/>
|
||||
<PackageReference Include="ProjNet.FSharp" Version="3.0.1"/>
|
||||
<PackageReference Include="sdslite" Version="2.2.0"/>
|
||||
<PackageReference Include="Serilog" Version="2.11.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.2-dev-00890"/>
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.1.2-dev-00222"/>
|
||||
<PackageReference Include="Thoth.Json.Net" Version="8.0.0"/>
|
||||
<PackageReference Include="MessagePack" Version="3.1.3"/>
|
||||
<PackageReference Include="ProjNet.FSharp" Version="5.2.0"/>
|
||||
<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 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>
|
||||
|
||||
66
src/Polygon.fs
Normal file
66
src/Polygon.fs
Normal file
@@ -0,0 +1,66 @@
|
||||
module Polygon
|
||||
|
||||
type Point = float * float
|
||||
|
||||
type Polygon = Point[]
|
||||
|
||||
let private maxdist (pol: Polygon) (pnt: Point) =
|
||||
pol
|
||||
|> Array.map (fun (x, y) -> sqrt ((x - fst pnt) ** 2.0 + (y - snd pnt) ** 2.0))
|
||||
|> Array.max
|
||||
|
||||
let private orientation (pol3: Polygon) =
|
||||
let diff seg =
|
||||
let px = seg |> Array.pairwise
|
||||
px |> Array.map (fun (x1, x2) -> x2 - x1)
|
||||
let x, y = pol3 |> Array.unzip
|
||||
let dx, dy = diff x, diff y
|
||||
let ori = dy[0] * dx[1] - dy[1] * dx[0]
|
||||
|
||||
if ori > 0.0 then 1
|
||||
elif ori < 0.0 then 2
|
||||
else 0
|
||||
|
||||
let private onsegment (p: Polygon) =
|
||||
let x, y = p |> Array.unzip
|
||||
let maxx = x[0..1] |> Array.max
|
||||
let minx = x[0..1] |> Array.min
|
||||
let maxy = y[0..1] |> Array.max
|
||||
let miny = y[0..1] |> Array.min
|
||||
|
||||
if x[2] >= minx && x[2] <= maxx && y[2] >= miny && y[2] <= maxy then
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
let private intersect (p1: Polygon) (p2: Polygon) =
|
||||
let x1, y1 = p1 |> Array.unzip
|
||||
let x2, y2 = p2 |> Array.unzip
|
||||
let pol1 = [| x1[0], y1[0]; x1[1], y1[1]; x2[0], y2[0] |]
|
||||
let pol2 = [| x1[0], y1[0]; x1[1], y1[1]; x2[1], y2[1] |]
|
||||
let pol3 = [| x2[0], y2[0]; x2[1], y2[1]; x1[0], y1[0] |]
|
||||
let pol4 = [| x2[0], y2[0]; x2[1], y2[1]; x1[1], y1[1] |]
|
||||
let o1, o2, o3, o4 =
|
||||
orientation pol1, orientation pol2, orientation pol3, orientation pol4
|
||||
|
||||
if o1 <> o2 && o3 <> o4 then true
|
||||
elif o1 = 0 && onsegment pol1 then true
|
||||
elif o2 = 0 && onsegment pol2 then true
|
||||
elif o3 = 0 && onsegment pol3 then true
|
||||
elif o4 = 0 && onsegment pol4 then true
|
||||
else false
|
||||
|
||||
let private isodd a = if a % 2 = 0 then false else true
|
||||
|
||||
let inpolygon (pol: Polygon) (point: Point) =
|
||||
let (line: Polygon) = [| fst point, snd point; fst point + (maxdist pol point), snd point |]
|
||||
let poly =
|
||||
if pol[0] <> pol[pol.Length - 1] then
|
||||
Array.append pol [| pol[0] |] |> Array.pairwise
|
||||
else
|
||||
pol |> Array.pairwise
|
||||
poly
|
||||
|> Array.map (fun (p1, p2) -> intersect line [| p1; p2 |])
|
||||
|> Array.map (fun x -> if x then 1 else 0)
|
||||
|> Array.sum
|
||||
|> isodd
|
||||
342
src/ROMS.fs
342
src/ROMS.fs
@@ -1,115 +1,90 @@
|
||||
module Oceanbox.FvcomKit.ROMS
|
||||
|
||||
open System.Diagnostics
|
||||
open FSharpPlus
|
||||
open Serilog
|
||||
open Microsoft.Research.Science.Data
|
||||
open MathNet.Numerics.LinearAlgebra
|
||||
open KdTree
|
||||
open ProjNet.FSharp
|
||||
|
||||
open Grid
|
||||
open Types
|
||||
open Adjoin
|
||||
open Interpol
|
||||
|
||||
type GridData<'a> = { rho: 'a; u: 'a; v: 'a }
|
||||
type private CropBox = (float * float) * (float * float)
|
||||
type private Mask = bool [,]
|
||||
type private PosVec = (float * float) []
|
||||
type private RomsPos = float [,] * float [,]
|
||||
type GridMask = GridData<bool [,]>
|
||||
type GridPos = GridData<RomsPos>
|
||||
type GridVars = GridData<float [,]>
|
||||
type GridMask = GridData<bool[,]>
|
||||
type GridPos = GridData<BiPos>
|
||||
type GridVars = GridData<float[,]>
|
||||
|
||||
type RomsGrid =
|
||||
{
|
||||
h: GridVars
|
||||
z: GridVars []
|
||||
pos: GridPos
|
||||
wetMask: GridMask
|
||||
angle: float [,]
|
||||
}
|
||||
type RomsGrid = {
|
||||
h: GridVars
|
||||
z: GridVars[]
|
||||
pos: GridPos
|
||||
wetMask: GridMask
|
||||
angle: float[,]
|
||||
}
|
||||
|
||||
type RomsProps =
|
||||
{
|
||||
salt: float [,] []
|
||||
temp: float [,] []
|
||||
zeta: float [,]
|
||||
u: float [,] []
|
||||
v: float [,] []
|
||||
}
|
||||
type RomsProps = {
|
||||
salt: float[,][]
|
||||
temp: float[,][]
|
||||
zeta: float[,]
|
||||
u: float[,][]
|
||||
v: float[,][]
|
||||
}
|
||||
|
||||
type AdjoinedProp =
|
||||
{
|
||||
salt: float [] []
|
||||
temp: float [] []
|
||||
zeta: float []
|
||||
u: float [] []
|
||||
v: float [] []
|
||||
}
|
||||
type AdjoinedProp = {
|
||||
salt: float[][]
|
||||
temp: float[][]
|
||||
zeta: float[]
|
||||
u: float[][]
|
||||
v: float[][]
|
||||
}
|
||||
|
||||
let private lngLatToUtm33 = ProjNet.FSharp.WGS84_TO_UTM 33
|
||||
|
||||
let private toUtm33 ((lng, lat): float [,] * float [,]) =
|
||||
lng
|
||||
|> Array2D.mapi (fun i j lon -> lon, lat[i, j])
|
||||
|> Array2D.map lngLatToUtm33.project
|
||||
|> unzip2D
|
||||
type FvcomGrid = Fvcom.FvcomGrid
|
||||
|
||||
let private layerZ csR (vars: GridVars) =
|
||||
let mult m x = Array2D.map ((*) x) m
|
||||
let rho = csR |> Array.map (mult vars.rho)
|
||||
let u = csR |> Array.map (mult vars.u)
|
||||
let v = csR |> Array.map (mult vars.v)
|
||||
Array.zip3 rho u v
|
||||
|> Array.map (fun (a, b, c) -> { rho = a; u = b; v = c })
|
||||
Array.zip3 rho u v |> Array.map (fun (a, b, c) -> { rho = a; u = b; v = c })
|
||||
|
||||
// convert fractional ROMS landmask to ocean mask
|
||||
let readWetMask (nc: DataSet) =
|
||||
let isWet = Array2D.map ((=) 1.)
|
||||
{
|
||||
rho = nc[ "mask_rho" ].GetData() :?> float [,] |> isWet
|
||||
u = nc[ "mask_u" ].GetData() :?> float [,] |> isWet
|
||||
v = nc[ "mask_v" ].GetData() :?> float [,] |> isWet
|
||||
rho = nc["mask_rho"].GetData () :?> float[,] |> isWet
|
||||
u = nc["mask_u"].GetData () :?> float[,] |> isWet
|
||||
v = nc["mask_v"].GetData () :?> float[,] |> isWet
|
||||
}
|
||||
|
||||
let private readProp3 (nc: DataSet) (p: string) t (prop: string) =
|
||||
let nEta = nc.Dimensions[$"eta_{p}"].Length
|
||||
let nXi = nc.Dimensions[$"xi_{p}"].Length
|
||||
let scaling =
|
||||
nc.Variables[prop].Metadata["scale_factor"] :?> single
|
||||
|> float
|
||||
let offset =
|
||||
nc.Variables[prop].Metadata["add_offset"] :?> single
|
||||
|> float
|
||||
let scaling = nc.Variables[prop].Metadata["scale_factor"] :?> single |> float
|
||||
let offset = nc.Variables[prop].Metadata["add_offset"] :?> single |> float
|
||||
let o = [| t; 0; 0 |]
|
||||
let shp = [| 1; nEta; nXi |]
|
||||
let convert (x: int16 [,,]) =
|
||||
x[0, *, *]
|
||||
|> Array2D.map (fun x -> float x * scaling + offset)
|
||||
nc[ prop ].GetData(o, shp) :?> int16 [,,]
|
||||
|> convert
|
||||
let convert (x: int16[,,]) =
|
||||
x[0, *, *] |> Array2D.map (fun x -> float x * scaling + offset)
|
||||
nc[prop].GetData (o, shp) :?> int16[,,] |> convert
|
||||
|
||||
let private readProp4 (nc: DataSet) (p: string) t (prop: string) =
|
||||
let nEta = nc.Dimensions[$"eta_{p}"].Length
|
||||
let nXi = nc.Dimensions[$"xi_{p}"].Length
|
||||
let nS = nc.Dimensions["s_rho"].Length
|
||||
let scaling =
|
||||
nc.Variables[prop].Metadata["scale_factor"] :?> single
|
||||
|> float
|
||||
let offset =
|
||||
nc.Variables[prop].Metadata["add_offset"] :?> single
|
||||
|> float
|
||||
let scaling = nc.Variables[prop].Metadata["scale_factor"] :?> single |> float
|
||||
let offset = nc.Variables[prop].Metadata["add_offset"] :?> single |> float
|
||||
let o = [| t; 0; 0; 0 |]
|
||||
let shp = [| 1; nS; nEta; nXi |]
|
||||
let convert (x: int16 [,,,]) =
|
||||
let convert (x: int16[,,,]) =
|
||||
x[0, *, *, *]
|
||||
|> Array3D.map (fun x -> float x * scaling + offset)
|
||||
|> fun m ->
|
||||
[|
|
||||
for z = 0 to nS - 1 do
|
||||
m[z, *, *]
|
||||
|]
|
||||
|> fun m -> [|
|
||||
for z = 0 to nS - 1 do
|
||||
m[z, *, *]
|
||||
|]
|
||||
|
||||
nc[ prop ].GetData(o, shp) :?> int16 [,,,]
|
||||
|> convert
|
||||
nc[prop].GetData (o, shp) :?> int16[,,,] |> convert
|
||||
|
||||
let readProps (nc: DataSet) t : RomsProps =
|
||||
Log.Information "Reading ROMS props..."
|
||||
@@ -128,177 +103,58 @@ let readVerticalGrid path =
|
||||
match Thredds.tryOpenArchive path with
|
||||
| Some ds -> ds
|
||||
| None -> failwith "open vertical grid failed"
|
||||
nc[ "Cs_r" ].GetData() :?> float [] |> Array.rev
|
||||
nc["s_rho"].GetData () :?> float[] |> Array.rev
|
||||
|
||||
let readGrid (nc: DataSet) =
|
||||
Log.Information "Reading ROMS grid..."
|
||||
|
||||
let hRho =
|
||||
nc[ "h" ].GetData() :?> float [,]
|
||||
|> Matrix.Build.DenseOfArray
|
||||
let hRho = nc["h"].GetData () :?> float[,] |> Matrix.Build.DenseOfArray
|
||||
|
||||
let csR = nc[ "Cs_r" ].GetData() :?> float [] |> Array.rev
|
||||
let srho = nc["s_rho"].GetData () :?> float[] |> Array.rev
|
||||
|
||||
let e1, e2 = hRho.ColumnCount - 2, hRho.RowCount - 2
|
||||
let hU = (hRho[*, 1..] + hRho[*, ..e1]) / 2.
|
||||
let hV = (hRho[1.., *] + hRho[..e2, *]) / 2.
|
||||
|
||||
let pos: GridPos =
|
||||
{
|
||||
rho = nc[ "lon_rho" ].GetData() :?> float [,], nc[ "lat_rho" ].GetData() :?> float [,]
|
||||
u = nc[ "lon_u" ].GetData() :?> float [,], nc[ "lat_u" ].GetData() :?> float [,]
|
||||
v = nc[ "lon_v" ].GetData() :?> float [,], nc[ "lat_v" ].GetData() :?> float [,]
|
||||
}
|
||||
let angle = nc[ "angle" ].GetData() :?> float [,]
|
||||
let h = { rho = hRho.ToArray(); u = hU.ToArray(); v = hV.ToArray() }
|
||||
let pos: GridPos = {
|
||||
rho = nc["lon_rho"].GetData () :?> float[,], nc["lat_rho"].GetData () :?> float[,]
|
||||
u = nc["lon_u"].GetData () :?> float[,], nc["lat_u"].GetData () :?> float[,]
|
||||
v = nc["lon_v"].GetData () :?> float[,], nc["lat_v"].GetData () :?> float[,]
|
||||
}
|
||||
let angle = nc["angle"].GetData () :?> float[,]
|
||||
let h = { rho = hRho.ToArray (); u = hU.ToArray (); v = hV.ToArray () }
|
||||
{
|
||||
h = h
|
||||
z = layerZ csR h
|
||||
z = layerZ srho h
|
||||
pos = pos
|
||||
wetMask = readWetMask nc
|
||||
angle = angle
|
||||
}
|
||||
|
||||
let private genCropIdx ((min, max): float * float) (m: float [,]) =
|
||||
[|
|
||||
for i = 0 to Array2D.length1 m - 1 do
|
||||
for j = 0 to Array2D.length2 m - 1 do
|
||||
if m[i, j] >= min && m[i, j] <= max then i, j else ()
|
||||
|]
|
||||
|> Set.ofArray
|
||||
|
||||
let private genCropMask ((xlim, ylim): CropBox) ((x, y): RomsPos) =
|
||||
let ind1 = genCropIdx xlim x
|
||||
let ind2 = genCropIdx ylim y
|
||||
Set.intersect ind1 ind2 |> Set.toArray
|
||||
|
||||
// compute a padded fvcom bounding box for cropping roms grids
|
||||
let private mkCropBox (box: BBox) : CropBox =
|
||||
let pad min max =
|
||||
let d = 5000.0
|
||||
float min - d, float max + d
|
||||
// let p = toUtm33 roms
|
||||
let xlim = pad box.minX box.maxX
|
||||
let ylim = pad box.minY box.maxY
|
||||
xlim, ylim
|
||||
|
||||
// make an array of indeces of wet roms grid points inside the fvcom domain
|
||||
let private genCullIdx (box: CropBox) (wet: Mask) (p: RomsPos) =
|
||||
genCropMask box p
|
||||
|> Array.filter (fun (i, j) -> wet[i, j])
|
||||
|
||||
// crop roms grid coordinates based in index mask of active, overlapping points
|
||||
let private cullCoords (p: RomsPos) (idx: (int * int) []) =
|
||||
let x, y = p
|
||||
let x' = idx |> Array.map (fun (i, j) -> x[i, j])
|
||||
let y' = idx |> Array.map (fun (i, j) -> y[i, j])
|
||||
Array.zip x' y'
|
||||
|
||||
// make a kd-tree for fast nearest neighbour lookup
|
||||
let private buildTree (points: (float * float) array) =
|
||||
let tree = KdTree<float, int>(2, KdTree.Math.DoubleMath())
|
||||
points
|
||||
|> Array.iteri (fun n (x, y) -> tree.Add([| x; y |], n) |> ignore)
|
||||
tree.Balance()
|
||||
tree
|
||||
|
||||
// adjoinIdx: index to culled roms grid for each fvcom node
|
||||
// cullIdx: index to roms points _actually_ in use
|
||||
// oobIdx: out-of-bounds points, too far from a roms cell
|
||||
type FvcomAdjoint = { adjoinIdx: int []; cullIdx: (int * int) []; oobIdx: int [] }
|
||||
|
||||
let private dist (a: float * float) (b: float * float) =
|
||||
let x0, y0 = a
|
||||
let x1, y1 = b
|
||||
let dX = x1 - x0
|
||||
let dY = y1 - y0
|
||||
dX ** 2 + dY ** 2 |> sqrt |> (*) 0.5
|
||||
|
||||
let private distLngLat (a: float * float) (b: float * float) =
|
||||
let x0, y0 = a |> lngLatToUtm33.project
|
||||
let x1, y1 = b |> lngLatToUtm33.project
|
||||
let dX = x1 - x0
|
||||
let dY = y1 - y0
|
||||
dX ** 2 + dY ** 2 |> sqrt |> (*) 0.5
|
||||
|
||||
let private genOobIdx (tree: KdTree<float, int>) (cullIdx: (int * int) []) (fPos: PosVec) (rPos: RomsPos) =
|
||||
let rLon, rLat = rPos
|
||||
let dMax = distLngLat (rLon[0, 0], rLat[0, 0]) (rLon[0, 1], rLat[0, 1])
|
||||
fPos
|
||||
|> Array.fold
|
||||
(fun (n, a) (x, y as p0) ->
|
||||
tree.GetNearestNeighbours([| x; y |], 1)
|
||||
|> fun p ->
|
||||
let i0, i1 = cullIdx[p[0].Value]
|
||||
let p1 = lngLatToUtm33.project ((rLon[i0, i1], rLat[i0, i1]))
|
||||
let d = dist p0 p1
|
||||
if d > dMax then n + 1, n :: a else n + 1, a)
|
||||
(0, [])
|
||||
|> snd
|
||||
|> Array.ofList
|
||||
|
||||
// compute the nearest neighbour index into the cropped roms grid
|
||||
let private mkFvcomAdjoint (fPos: PosVec) (bbox: BBox) ((rPos, wet): RomsPos * Mask) =
|
||||
let box = mkCropBox bbox
|
||||
let pos' = toUtm33 rPos
|
||||
let cullIdx = genCullIdx box wet pos'
|
||||
let tree = cullCoords pos' cullIdx |> buildTree
|
||||
let nearest =
|
||||
fPos
|
||||
|> Array.map (fun (x, y) ->
|
||||
tree.GetNearestNeighbours([| x; y |], 1)
|
||||
|> fun x -> x[0].Value)
|
||||
{
|
||||
adjoinIdx = nearest
|
||||
cullIdx = cullIdx
|
||||
oobIdx = genOobIdx tree cullIdx fPos rPos
|
||||
}
|
||||
|
||||
let private getNearestNode (fvcom: Grid) (roms: RomsPos * Mask) =
|
||||
let fvNodes = Array.map (fun (x, y) -> float x, float y) fvcom.Nodes
|
||||
mkFvcomAdjoint fvNodes fvcom.BBox roms
|
||||
|
||||
// same as getNearestNode, but for uv in the center of a cell/element
|
||||
let private getNearestCell (fvcom: Grid) (roms: RomsPos * Mask) =
|
||||
let fvCells = Array.map (fun (x, y) -> float x, float y) fvcom.Cells
|
||||
mkFvcomAdjoint fvCells fvcom.BBox roms
|
||||
|
||||
// pick out elements actually in use
|
||||
let inline private cullRomsMatrix (culler: (int * int) []) (m: 'a [,]) =
|
||||
culler |> Array.map (fun (i, j) -> m[i, j])
|
||||
|
||||
// adjoin fvcom and roms data based on nearest neighbours
|
||||
let private adjoinMatrix (adj: FvcomAdjoint) (m: 'a [,]) =
|
||||
let x = cullRomsMatrix adj.cullIdx m
|
||||
adj.adjoinIdx |> Array.map (fun n -> x[n])
|
||||
|
||||
type IRomsToFvcom =
|
||||
abstract uv: bool
|
||||
abstract rhoToFvcom: 'a [,] -> 'a []
|
||||
abstract uToFvcom: 'a [,] -> 'a []
|
||||
abstract vToFvcom: 'a [,] -> 'a []
|
||||
abstract rhoToFvcom: 'a[,] -> 'a[]
|
||||
abstract uToFvcom: 'a[,] -> 'a[]
|
||||
abstract vToFvcom: 'a[,] -> 'a[]
|
||||
abstract rhoAdjoint: FvcomAdjoint
|
||||
abstract uAdjoint: FvcomAdjoint
|
||||
abstract vAdjoint: FvcomAdjoint
|
||||
|
||||
type AdjoinedGrid =
|
||||
{
|
||||
h: float []
|
||||
zRho: float [] []
|
||||
zU: float [] []
|
||||
zV: float [] []
|
||||
angle: float []
|
||||
u: float []
|
||||
v: float []
|
||||
}
|
||||
type AdjoinedGrid = {
|
||||
h: float[]
|
||||
zRho: float[][]
|
||||
zU: float[][]
|
||||
zV: float[][]
|
||||
angle: float[]
|
||||
u: float[]
|
||||
v: float[]
|
||||
}
|
||||
|
||||
let adjoinGirds (r2f: IRomsToFvcom) (roms: RomsGrid) =
|
||||
Log.Information "Adjoining grids."
|
||||
{
|
||||
h = r2f.rhoToFvcom roms.h.rho
|
||||
zRho =
|
||||
roms.z
|
||||
|> Array.map (fun h -> r2f.rhoToFvcom h.rho)
|
||||
zRho = roms.z |> Array.map (fun h -> r2f.rhoToFvcom h.rho)
|
||||
zU = roms.z |> Array.map (fun h -> r2f.uToFvcom h.u)
|
||||
zV = roms.z |> Array.map (fun h -> r2f.vToFvcom h.v)
|
||||
angle = r2f.rhoToFvcom roms.angle
|
||||
@@ -316,32 +172,31 @@ let adjoinProps (r2f: IRomsToFvcom) (props: RomsProps) =
|
||||
v = Array.map r2f.vToFvcom props.v
|
||||
}
|
||||
|
||||
let genRomsToFvcomAdjoints (fvcom: Grid) (roms: RomsGrid) =
|
||||
let rhoM = getNearestNode fvcom (roms.pos.rho, roms.wetMask.rho)
|
||||
let genRomsToFvcomAdjoints (proj: IProj) (fvcom: Grid) (roms: RomsGrid) =
|
||||
let rhoM = getNearestNode proj fvcom (roms.pos.rho, roms.wetMask.rho)
|
||||
let uvMappings =
|
||||
let uM = getNearestCell fvcom (roms.pos.u, roms.wetMask.u)
|
||||
let vM = getNearestCell fvcom (roms.pos.v, roms.wetMask.v)
|
||||
let uM = getNearestCell proj fvcom (roms.pos.u, roms.wetMask.u)
|
||||
let vM = getNearestCell proj fvcom (roms.pos.v, roms.wetMask.v)
|
||||
uM, vM
|
||||
{ new IRomsToFvcom with
|
||||
member x.uv = true
|
||||
member x.rhoToFvcom m = adjoinMatrix rhoM m
|
||||
member x.uToFvcom m = adjoinMatrix (fst uvMappings) m
|
||||
member x.vToFvcom m = adjoinMatrix (snd uvMappings) m
|
||||
member x.rhoAdjoint = rhoM
|
||||
member x.uAdjoint = fst uvMappings
|
||||
member x.vAdjoint = snd uvMappings
|
||||
member this.uv = true
|
||||
member this.rhoToFvcom m = adjoinMatrix rhoM m
|
||||
member this.uToFvcom m = adjoinMatrix (fst uvMappings) m
|
||||
member this.vToFvcom m = adjoinMatrix (snd uvMappings) m
|
||||
member this.rhoAdjoint = rhoM
|
||||
member this.uAdjoint = fst uvMappings
|
||||
member this.vAdjoint = snd uvMappings
|
||||
}
|
||||
|
||||
let adjoinRomsToFvcom (fvcom: Grid) (roms: RomsGrid) (props: RomsProps) =
|
||||
let r2f = genRomsToFvcomAdjoints fvcom roms
|
||||
let adjoinRomsToFvcom (proj: IProj) (fvcom: Grid) (roms: RomsGrid) (props: RomsProps) =
|
||||
let r2f = genRomsToFvcomAdjoints proj fvcom roms
|
||||
adjoinGirds r2f roms, adjoinProps r2f props
|
||||
|
||||
let computeAngles (grid: Grid) (adj: AdjoinedGrid) =
|
||||
let computeAngles (grid: FvcomGrid) (adj: AdjoinedGrid) =
|
||||
let a = adj.angle
|
||||
grid.Elem
|
||||
|> Array.map (fun (i, j, k) -> (a[i] + a[j] + a[k]) / 3.0)
|
||||
grid.Elem |> Array.map (fun (i, j, k) -> (a[i] + a[j] + a[k]) / 3.0)
|
||||
|
||||
let calcUVBar (fvcom: Grid) (u, v) =
|
||||
let calcUVBar (fvcom: FvcomGrid) (u, v) =
|
||||
let h = fvcom.Bathymetry
|
||||
let s = fvcom.Siglev
|
||||
let nZ = Array2D.length1 s
|
||||
@@ -353,24 +208,29 @@ let calcUVBar (fvcom: Grid) (u, v) =
|
||||
[|
|
||||
for z = 0 to nZ - 1 do
|
||||
fvcom.Elem
|
||||
|> Array.mapi (fun n (i, j, k) ->
|
||||
hc[n] * (s[z, i] + s[z, j] + s[z, k] |> float)
|
||||
/ 3.0)
|
||||
|> Array.mapi (fun n (i, j, k) -> hc[n] * (s[z, i] + s[z, j] + s[z, k] |> float) / 3.0)
|
||||
|]
|
||||
|> matrix
|
||||
let dz =
|
||||
sigz.ToColumnArrays()
|
||||
|> Array.map (
|
||||
Array.pairwise
|
||||
>> Array.map (fun (x0, x1) -> x1 - x0)
|
||||
)
|
||||
sigz.ToColumnArrays ()
|
||||
|> Array.map (Array.pairwise >> Array.map (fun (x0, x1) -> x1 - x0))
|
||||
|> matrix
|
||||
|> fun x -> x.PointwiseAbs().Transpose()
|
||||
|> fun x -> x.PointwiseAbs().Transpose ()
|
||||
let bar (m: Matrix<float>) =
|
||||
m.PointwiseMultiply dz
|
||||
|> fun x ->
|
||||
let s = x.ColumnSums()
|
||||
let s = x.ColumnSums ()
|
||||
s.PointwiseDivide hc
|
||||
let u' = Matrix.Build.DenseOfRowArrays u
|
||||
let v' = Matrix.Build.DenseOfRowArrays v
|
||||
bar u', bar v'
|
||||
|
||||
// Linear interpolation to nearest vertical neighbor
|
||||
let mkAllDepthInterpolCoefs (fvcom: Fvcom.FvcomGrid) (roms: AdjoinedGrid) =
|
||||
Log.Information "Computing interpolation coefficients."
|
||||
let uv = Array.zip roms.u roms.v |> Array.map (fun (u, v) -> (u + v) * 0.5)
|
||||
{
|
||||
iRho = mkDepthInterpolCoefs fvcom.Siglay roms.h roms.zRho
|
||||
iU = mkDepthInterpolCoefs fvcom.SiglayCenter uv roms.zU
|
||||
iV = mkDepthInterpolCoefs fvcom.SiglayCenter uv roms.zV
|
||||
}
|
||||
@@ -1,66 +1,67 @@
|
||||
module Oceanbox.FvcomKit.Smoothing
|
||||
|
||||
open Fvcom
|
||||
open Oceanbox.FvcomKit.Grid
|
||||
open Serilog
|
||||
open Grid
|
||||
open ProjNet.FSharp
|
||||
|
||||
let private OOBVAL = -100000f
|
||||
|
||||
let smooth (prop: single []) source =
|
||||
let smooth (prop: single[]) source =
|
||||
source
|
||||
|> Array.fold (fun a x -> a + prop[x]) 0f
|
||||
|> fun x -> x / single source.Length
|
||||
|
||||
let smooth' (prop: single []) source =
|
||||
let smooth' (prop: single[]) source =
|
||||
source
|
||||
|> Array.fold (fun (n, a) x -> if prop[x] > OOBVAL then n + 1, a + prop[x] else n, a) (0, 0f)
|
||||
|> fun (n, a) -> a / single n
|
||||
|
||||
let smoothNodes (iGrid: IndexedFvcomGrid) (prop: single []) =
|
||||
iGrid.NodesAroundNode.Values
|
||||
|> Seq.toArray
|
||||
|> Array.Parallel.map (smooth prop)
|
||||
let smoothNodes (idx: NeighborIndex) (prop: single[]) =
|
||||
idx.NodesAroundNode.Values |> Seq.toArray |> Array.Parallel.map (smooth prop)
|
||||
|
||||
let smoothNodes2D (iGrid: IndexedFvcomGrid) (prop: single [,]) =
|
||||
let smoothNodes2D (idx: NeighborIndex) (prop: single[,]) =
|
||||
for k = 0 to Array2D.length1 prop - 1 do
|
||||
Log.Debug $"2D smoothing nodes z = {k}"
|
||||
prop[k, *] <- iGrid.NodesAroundNode.Values
|
||||
|> Seq.toArray
|
||||
|> Array.Parallel.map (smooth prop[k, *])
|
||||
prop[k, *] <-
|
||||
idx.NodesAroundNode.Values
|
||||
|> Seq.toArray
|
||||
|> Array.Parallel.map (smooth prop[k, *])
|
||||
prop
|
||||
|
||||
let smoothNodes3D (iGrid: IndexedFvcomGrid) (prop: single [,,]) =
|
||||
let smoothNodes3D (idx: NeighborIndex) (prop: single[,,]) =
|
||||
for k = 0 to Array3D.length1 prop - 1 do
|
||||
for n = 0 to Array3D.length2 prop - 1 do
|
||||
Log.Debug $"3D smoothing nodes z = {n}"
|
||||
prop[k, n, *] <- iGrid.NodesAroundNode.Values
|
||||
|> Seq.toArray
|
||||
|> Array.Parallel.map (smooth prop[k, n, *])
|
||||
prop[k, n, *] <-
|
||||
idx.NodesAroundNode.Values
|
||||
|> Seq.toArray
|
||||
|> Array.Parallel.map (smooth prop[k, n, *])
|
||||
prop
|
||||
|
||||
let smoothElements (iGrid: IndexedFvcomGrid) (prop: single []) =
|
||||
iGrid.Grid.Elem
|
||||
let smoothElements (idx: NeighborIndex) (grid: Grid) (prop: single[]) =
|
||||
grid.Elem
|
||||
|> Array.Parallel.mapi (fun n _ ->
|
||||
let elems = Grid.getElemsSurroundingElem iGrid n
|
||||
let elems = getElemsSurroundingElem idx grid n
|
||||
smooth prop elems)
|
||||
|
||||
let smoothElements2D (iGrid: IndexedFvcomGrid) (prop: single [,]) =
|
||||
let smoothElements2D (idx: NeighborIndex) (grid: Grid) (prop: single[,]) =
|
||||
for k = 0 to Array2D.length1 prop - 1 do
|
||||
Log.Debug $"2D smoothing elements z = {k}"
|
||||
prop[k, *] <- smoothElements iGrid prop[k, *]
|
||||
prop[k, *] <- smoothElements idx grid prop[k, *]
|
||||
prop
|
||||
|
||||
let smoothElements3D (iGrid: IndexedFvcomGrid) (prop: single [,,]) =
|
||||
let smoothElements3D (idx: NeighborIndex) (grid: Grid) (prop: single[,,]) =
|
||||
for k = 0 to Array3D.length1 prop - 1 do
|
||||
for n = 0 to Array3D.length2 prop - 1 do
|
||||
Log.Debug $"3D smoothing elements z = {n}"
|
||||
prop[k, n, *] <- smoothElements iGrid prop[k, n, *]
|
||||
prop[k, n, *] <- smoothElements idx grid prop[k, n, *]
|
||||
prop
|
||||
|
||||
let private rectifyOob (getSurrounding: int -> int []) (oob: int []) (prop: single []) =
|
||||
let private rectifyOob (getSurrounding: int -> int[]) (oob: int[]) (prop: single[]) =
|
||||
for i in oob do
|
||||
prop[i] <- OOBVAL // reset
|
||||
let rec rectify (oob: int []) =
|
||||
let rec rectify (oob: int[]) =
|
||||
Log.Debug $"rectify oob remaining {oob.Length}"
|
||||
for n in oob do
|
||||
let ns = getSurrounding n
|
||||
@@ -72,59 +73,36 @@ let private rectifyOob (getSurrounding: int -> int []) (oob: int []) (prop: sing
|
||||
rectify oob
|
||||
prop
|
||||
|
||||
let rectifyOutOfBoundsNodes (iGrid: IndexedFvcomGrid) (oob: int []) (prop: single []) =
|
||||
let f = Grid.getNodesSurroundingNode iGrid
|
||||
let rectifyOutOfBoundsNodes (idx: NeighborIndex) (oob: int[]) (prop: single[]) =
|
||||
let f = getNodesSurroundingNode idx
|
||||
rectifyOob f oob prop
|
||||
|
||||
let rectifyOutOfBoundsNodes2D (iGrid: IndexedFvcomGrid) (oob: int []) (prop: single [,]) =
|
||||
let f = Grid.getNodesSurroundingNode iGrid
|
||||
let rectifyOutOfBoundsNodes2D (idx: NeighborIndex) (oob: int[]) (prop: single[,]) =
|
||||
let f = getNodesSurroundingNode idx
|
||||
for k = 0 to Array2D.length1 prop - 1 do
|
||||
prop[k, *] <- rectifyOob f oob prop[k, *]
|
||||
prop
|
||||
|
||||
let rectifyOutOfBoundsNodes3D (iGrid: IndexedFvcomGrid) (oob: int []) (prop: single [,,]) =
|
||||
let f = Grid.getNodesSurroundingNode iGrid
|
||||
let rectifyOutOfBoundsNodes3D (idx: NeighborIndex) (oob: int[]) (prop: single[,,]) =
|
||||
let f = getNodesSurroundingNode idx
|
||||
for k = 0 to Array3D.length1 prop - 1 do
|
||||
for n = 0 to Array3D.length2 prop - 1 do
|
||||
prop[k, n, *] <- rectifyOob f oob prop[k, n, *]
|
||||
prop
|
||||
|
||||
let rectifyOutOfBoundsElements (iGrid: IndexedFvcomGrid) (oob: int []) (prop: single []) =
|
||||
let f = Grid.getElemsSurroundingElem iGrid
|
||||
let rectifyOutOfBoundsElements (idx: NeighborIndex) (grid: Grid) (oob: int[]) (prop: single[]) =
|
||||
let f = getElemsSurroundingElem idx grid
|
||||
rectifyOob f oob prop
|
||||
|
||||
let rectifyOutOfBoundsElements2D (iGrid: IndexedFvcomGrid) (oob: int []) (prop: single [,]) =
|
||||
let f = Grid.getElemsSurroundingElem iGrid
|
||||
let rectifyOutOfBoundsElements2D (idx: NeighborIndex) (grid: Grid) (oob: int[]) (prop: single[,]) =
|
||||
let f = getElemsSurroundingElem idx grid
|
||||
for k = 0 to Array2D.length1 prop - 1 do
|
||||
prop[k, *] <- rectifyOob f oob prop[k, *]
|
||||
prop
|
||||
|
||||
let rectifyOutOfBoundsElements3D (iGrid: IndexedFvcomGrid) (oob: int []) (prop: single [,,]) =
|
||||
let f = Grid.getElemsSurroundingElem iGrid
|
||||
let rectifyOutOfBoundsElements3D (idx: NeighborIndex) (grid: Grid) (oob: int[]) (prop: single[,,]) =
|
||||
let f = getElemsSurroundingElem idx grid
|
||||
for k = 0 to Array3D.length1 prop - 1 do
|
||||
for n = 0 to Array3D.length2 prop - 1 do
|
||||
prop[k, n, *] <- rectifyOob f oob prop[k, n, *]
|
||||
prop
|
||||
|
||||
let rectifyOutOfBoundProps fvcom rGrid iGrid (x: FvcomRestart) =
|
||||
let a = ROMS.genRomsToFvcomAdjoints fvcom rGrid
|
||||
{ x with
|
||||
salinity = rectifyOutOfBoundsNodes3D iGrid a.rhoAdjoint.oobIdx x.salinity
|
||||
temp = rectifyOutOfBoundsNodes3D iGrid a.rhoAdjoint.oobIdx x.temp
|
||||
zeta = rectifyOutOfBoundsNodes2D iGrid a.rhoAdjoint.oobIdx x.zeta
|
||||
u = rectifyOutOfBoundsElements3D iGrid a.uAdjoint.oobIdx x.u
|
||||
v = rectifyOutOfBoundsElements3D iGrid a.vAdjoint.oobIdx x.v
|
||||
ua = rectifyOutOfBoundsElements2D iGrid a.uAdjoint.oobIdx x.ua
|
||||
va = rectifyOutOfBoundsElements2D iGrid a.vAdjoint.oobIdx x.va
|
||||
}
|
||||
|
||||
let smoothProps iGrid (x: FvcomRestart) =
|
||||
{ x with
|
||||
salinity = smoothNodes3D iGrid x.salinity
|
||||
temp = smoothNodes3D iGrid x.temp
|
||||
zeta = smoothNodes2D iGrid x.zeta
|
||||
u = smoothElements3D iGrid x.u
|
||||
v = smoothElements3D iGrid x.v
|
||||
ua = smoothElements2D iGrid x.ua
|
||||
va = smoothElements2D iGrid x.va
|
||||
}
|
||||
prop
|
||||
@@ -1,6 +1,7 @@
|
||||
module Oceanbox.FvcomKit.Thredds
|
||||
|
||||
open System
|
||||
|
||||
open Microsoft.Research.Science.Data
|
||||
open Microsoft.Research.Science.Data.NetCDF4
|
||||
open Serilog
|
||||
@@ -21,21 +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
|
||||
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
|
||||
List.unfold (fun d -> if d > days then None else Some (start.AddDays d, d + 1)) 0
|
||||
|
||||
let tryOpenArchive url =
|
||||
let uri = NetCDFUri()
|
||||
uri.Url <- url
|
||||
let tryOpenArchive url : DataSet option =
|
||||
let uri = NetCDFUri ()
|
||||
do uri.Url <- url
|
||||
try
|
||||
let ds = NetCDFDataSet.Open uri
|
||||
Some ds
|
||||
with
|
||||
| e ->
|
||||
Log.Debug e.Message
|
||||
with e ->
|
||||
do Log.Debug e.Message
|
||||
None
|
||||
|
||||
let rec tryOpenThredds =
|
||||
@@ -43,18 +43,22 @@ let rec tryOpenThredds =
|
||||
| [] -> None
|
||||
| x :: xs ->
|
||||
match tryOpenArchive x with
|
||||
| None ->
|
||||
tryOpenThredds xs
|
||||
| Some ds ->
|
||||
Log.Debug $"thredds: {x}"
|
||||
Some(x, ds)
|
||||
| None -> tryOpenThredds xs
|
||||
do Log.Debug $"thredds: {x}"
|
||||
Some (x, ds)
|
||||
|
||||
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 ot = ds["ocean_time"].GetData () :?> double[]
|
||||
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
|
||||
|
||||
27
src/Types.fs
27
src/Types.fs
@@ -2,8 +2,26 @@ module Oceanbox.FvcomKit.Types
|
||||
|
||||
open System
|
||||
|
||||
type Vertex = float * float
|
||||
|
||||
let unzip2D (array: _ [,]) =
|
||||
[<Struct>]
|
||||
type BBox = {
|
||||
minX: float
|
||||
maxX: float
|
||||
minY: float
|
||||
maxY: float
|
||||
center: float * float
|
||||
} with
|
||||
static member empty = {
|
||||
minX = Double.MaxValue
|
||||
maxX = Double.MinValue
|
||||
minY = Double.MaxValue
|
||||
maxY = Double.MinValue
|
||||
center = 0, 0
|
||||
}
|
||||
|
||||
|
||||
let unzip2D (array: _[,]) =
|
||||
let len1 = Array2D.length1 array
|
||||
let len2 = Array2D.length2 array
|
||||
let res1 = Array2D.zeroCreate len1 len2
|
||||
@@ -15,7 +33,7 @@ let unzip2D (array: _ [,]) =
|
||||
res2[i, j] <- y
|
||||
res1, res2
|
||||
|
||||
let inline propTo3D (p: 'a [,]) =
|
||||
let inline propTo3D (p: 'a[,]) =
|
||||
let z = Array2D.length1 p
|
||||
let n = Array2D.length2 p
|
||||
let m = Array3D.zeroCreate 1 z n
|
||||
@@ -24,10 +42,13 @@ let inline propTo3D (p: 'a [,]) =
|
||||
m[0, i, j] <- p[i, j] |> single
|
||||
m
|
||||
|
||||
let inline propTo2D (p: 'a []) =
|
||||
let inline propTo2D (p: 'a[]) =
|
||||
let n = p.Length
|
||||
let m = Array2D.zeroCreate 1 n
|
||||
for i = 0 to n - 1 do
|
||||
m[0, i] <- p[i] |> single
|
||||
m
|
||||
|
||||
let inline trace s x =
|
||||
printfn s
|
||||
x
|
||||
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,409 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net6.0": {
|
||||
"FSharp.Core": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.0.4-beta.22181.2, )",
|
||||
"resolved": "6.0.4-beta.22181.2",
|
||||
"contentHash": "r2po3cDh7SvAQJAozPxlThH/aReaRMl0W5AqeMBE/pbLcJWoeavYpRWhs5VYdqJynxe9h2sgKvLIXa7zp7QhUw=="
|
||||
},
|
||||
"FSharp.Data": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.2.8, )",
|
||||
"resolved": "4.2.8",
|
||||
"contentHash": "iSMHBxtovIvgMbMtJHetk2+pqDsVH4VBnz0VXkJ8wsnY9FYA2yaKU9Ntlg25Z383IWO/xBmLaBxw6QrpAT7g+g==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2"
|
||||
}
|
||||
},
|
||||
"FSharpPlus": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.2.3.1-PR476-02311, )",
|
||||
"resolved": "1.2.3.1-PR476-02311",
|
||||
"contentHash": "dWAE0e24fgMMod3fPP6qS2Qn7AkhwweunhjSOsZ7dZAZIuxhSB+33x0TNLM6YUPOJmgkpsURs6aqY0RRDM+P7A==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.6.2"
|
||||
}
|
||||
},
|
||||
"KdTree": {
|
||||
"type": "Direct",
|
||||
"requested": "[1.4.1, )",
|
||||
"resolved": "1.4.1",
|
||||
"contentHash": "yWbb35v/V9y88SLLMUPTlAN3pQEoPhDfZf9PApFnlU4kLtwVQ75U9vW5mW4/alQnLBuLKWBKcy4W5xK95mYsuA=="
|
||||
},
|
||||
"MathNet.Numerics.FSharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[5.0.0, )",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "lKYhd68fReW5odX/q+Uzxw3357Duq3zmvkYvnZVqqcc2r/EmrYGDoOdUGuHnhfr8yj9V34js5gQH/7IWcxZJxg==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.2",
|
||||
"MathNet.Numerics": "5.0.0"
|
||||
}
|
||||
},
|
||||
"ProjNet.FSharp": {
|
||||
"type": "Direct",
|
||||
"requested": "[3.0.1, )",
|
||||
"resolved": "3.0.1",
|
||||
"contentHash": "KU5y56kTrmHZVHyZQujQyhOf9PXscT7JR1dvJ0S1A8d23w79iB0nam1g8mtxHJWWDLIb1K2Bs54G+zynD4DLIQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "6.0.2",
|
||||
"FSharp.Data": "4.2.7",
|
||||
"FSharpPlus": "1.2.2",
|
||||
"ProjNet": "2.0.0"
|
||||
}
|
||||
},
|
||||
"SDSLite": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.2.0, )",
|
||||
"resolved": "2.2.0",
|
||||
"contentHash": "g4y+GyW8sAfF4b5Kwm0sTw/07rPHrtcgxqb7KzUxJsU8C7+k0GpCZwKc6Qs3wPgzKnAkdQfpP0Fa+Yrjkvxjhg==",
|
||||
"dependencies": {
|
||||
"DynamicInterop": "0.9.1"
|
||||
}
|
||||
},
|
||||
"Serilog": {
|
||||
"type": "Direct",
|
||||
"requested": "[2.11.0, )",
|
||||
"resolved": "2.11.0",
|
||||
"contentHash": "ysv+hBzTul6Dp+Hvm10FlhJO3yMQcFKSAleus+LpiIzvNstpeV4Z7gGuIZ1OPNfIMulSHOjmLuGAEDKzpnV8ZQ=="
|
||||
},
|
||||
"Serilog.Sinks.Console": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.0.2-dev-00890, )",
|
||||
"resolved": "4.0.2-dev-00890",
|
||||
"contentHash": "5l0OWV0dk0fAzascJUY0tWrAPqrleSs2uhZzW2y9iYXFYtEfMBPTi1+UHPO6Pa76Z4ZG06s2mpGfjAdPSpIxNw==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.Seq": {
|
||||
"type": "Direct",
|
||||
"requested": "[5.1.2-dev-00222, )",
|
||||
"resolved": "5.1.2-dev-00222",
|
||||
"contentHash": "Ef/wXQM2/jj7YK1xsiew5SUkHoORVLxvTyYWrqls+3SgKrWWvrOksVuRADhAZsGihZZ1hOMDrN00y4ycQl10NQ==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.10.0",
|
||||
"Serilog.Formatting.Compact": "1.1.0",
|
||||
"Serilog.Sinks.File": "4.0.0",
|
||||
"Serilog.Sinks.PeriodicBatching": "2.3.0"
|
||||
}
|
||||
},
|
||||
"Thoth.Json.Net": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.0, )",
|
||||
"resolved": "8.0.0",
|
||||
"contentHash": "C/b+8g/xUTJTn7pbKC4bMAOy2tyolXAuHTXguT5TNzDKQ6sjnUfFa9B81fTt9PuUOdWFLyRKlXASuFhSQciJGQ==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.7.2",
|
||||
"Fable.Core": "[3.0.0, 4.0.0)",
|
||||
"Newtonsoft.Json": "11.0.2"
|
||||
}
|
||||
},
|
||||
"DynamicInterop": {
|
||||
"type": "Transitive",
|
||||
"resolved": "0.9.1",
|
||||
"contentHash": "n21+Hd+tceX8lgaOosPV+Pne+YqnZUd5RLW3OhnsVxWRzYXiAIAKmKweHIePYeY+fmcn3N5tjkJyQUccFuL3bg=="
|
||||
},
|
||||
"Fable.Core": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.0.0",
|
||||
"contentHash": "pkCOWJKAkCk36f5+q4F3XqlfsgCJL6i2lTLl4ZZVDswn8rjXo21EBG/gJ296a88LVBkI5LL2VwxQYqGZncomJw==",
|
||||
"dependencies": {
|
||||
"FSharp.Core": "4.5.2"
|
||||
}
|
||||
},
|
||||
"MathNet.Numerics": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.0.0",
|
||||
"contentHash": "pg1W2VwaEQMAiTpGK840hZgzavnqjlCMTVSbtVCXVyT+7AX4mc1o89SPv4TBlAjhgCOo9c1Y+jZ5m3ti2YgGgA=="
|
||||
},
|
||||
"Microsoft.NETCore.Platforms": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.1",
|
||||
"contentHash": "2G6OjjJzwBfNOO8myRV/nFrbTw5iA+DEm0N+qUqhrOmaVtn4pC77h38I1jsXGw5VH55+dPfQsqHD0We9sCl9FQ=="
|
||||
},
|
||||
"Microsoft.NETCore.Targets": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.0.1",
|
||||
"contentHash": "rkn+fKobF/cbWfnnfBOQHKVKIOpxMZBvlSHkqDWgBpwGDcLRduvs3D9OLGeV6GWGvVwNlVi2CBbTjuPmtHvyNw=="
|
||||
},
|
||||
"Newtonsoft.Json": {
|
||||
"type": "Transitive",
|
||||
"resolved": "11.0.2",
|
||||
"contentHash": "IvJe1pj7JHEsP8B8J8DwlMEx8UInrs/x+9oVY+oCD13jpLu4JbJU2WCIsMRn5C4yW9+DgkaO8uiVE5VHKjpmdQ=="
|
||||
},
|
||||
"ProjNET": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.0.0",
|
||||
"contentHash": "iMJG8qpGJ8SjFrB044O8wgo0raAWCdG1Bvly0mmVcjzsrexDHhC+dUct6Wb1YwQtupMBjSTWq7Fn00YeNErprA==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.3",
|
||||
"System.Numerics.Vectors": "4.5.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Formatting.Compact": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.0",
|
||||
"contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.8.0"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.File": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.0",
|
||||
"contentHash": "vBj43RkAbeP1dzoPFR2+LfV5GevDRPDq6265JJBv223lMvT9rfdwe/S/I9ow7aZSLYKfw4qPDw6NW8YwjbDbvg==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.5.0",
|
||||
"System.IO": "4.1.0",
|
||||
"System.IO.FileSystem": "4.0.1",
|
||||
"System.IO.FileSystem.Primitives": "4.0.1",
|
||||
"System.Runtime.InteropServices": "4.1.0",
|
||||
"System.Text.Encoding.Extensions": "4.0.11",
|
||||
"System.Threading": "4.0.11",
|
||||
"System.Threading.Timer": "4.0.1"
|
||||
}
|
||||
},
|
||||
"Serilog.Sinks.PeriodicBatching": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.3.0",
|
||||
"contentHash": "UYKSjTMTlUY9T3OgzMmLDLD+z0qPfgvq/RvG0rKfyz+O+Zrjw3X/Xpv14J4WMcGVsOjUaR+k8n2MdmqVpJtI6A==",
|
||||
"dependencies": {
|
||||
"Serilog": "2.0.0",
|
||||
"System.Collections.Concurrent": "4.0.12",
|
||||
"System.Threading.Timer": "4.0.1"
|
||||
}
|
||||
},
|
||||
"System.Collections": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.11",
|
||||
"contentHash": "YUJGz6eFKqS0V//mLt25vFGrrCvOnsXjlvFQs+KimpwNxug9x0Pzy4PlFMU3Q2IzqAa9G2L4LsK3+9vCBK7oTg==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Collections.Concurrent": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.12",
|
||||
"contentHash": "2gBcbb3drMLgxlI0fBfxMA31ec6AEyYCHygGse4vxceJan8mRIWeKJ24BFzN7+bi/NFTgdIgufzb94LWO5EERQ==",
|
||||
"dependencies": {
|
||||
"System.Collections": "4.0.11",
|
||||
"System.Diagnostics.Debug": "4.0.11",
|
||||
"System.Diagnostics.Tracing": "4.1.0",
|
||||
"System.Globalization": "4.0.11",
|
||||
"System.Reflection": "4.1.0",
|
||||
"System.Resources.ResourceManager": "4.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Runtime.Extensions": "4.1.0",
|
||||
"System.Threading": "4.0.11",
|
||||
"System.Threading.Tasks": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.Debug": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.11",
|
||||
"contentHash": "w5U95fVKHY4G8ASs/K5iK3J5LY+/dLFd4vKejsnI/ZhBsWS9hQakfx3Zr7lRWKg4tAw9r4iktyvsTagWkqYCiw==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Diagnostics.Tracing": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "vDN1PoMZCkkdNjvZLql592oYJZgS7URcJzJ7bxeBgGtx5UtR5leNm49VmfHGqIffX4FKacHbI3H6UyNSHQknBg==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Globalization": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.11",
|
||||
"contentHash": "B95h0YLEL2oSnwF/XjqSWKnwKOy/01VWkNlsCeMTFJLLabflpGV26nK164eRs5GiaRSBGpOxQ3pKoSnnyZN5pg==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.IO": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "3KlTJceQc3gnGIaHZ7UBZO26SHL1SHE4ddrmiwumFnId+CEHP+O8r386tZKaE6zlk5/mF8vifMBzHj9SaXN+mQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Text.Encoding": "4.0.11",
|
||||
"System.Threading.Tasks": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.IO.FileSystem": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.1",
|
||||
"contentHash": "IBErlVq5jOggAD69bg1t0pJcHaDbJbWNUZTPI96fkYWzwYbN6D9wRHMULLDd9dHsl7C2YsxXL31LMfPI1SWt8w==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.IO": "4.1.0",
|
||||
"System.IO.FileSystem.Primitives": "4.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Runtime.Handles": "4.0.1",
|
||||
"System.Text.Encoding": "4.0.11",
|
||||
"System.Threading.Tasks": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.IO.FileSystem.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.1",
|
||||
"contentHash": "kWkKD203JJKxJeE74p8aF8y4Qc9r9WQx4C0cHzHPrY3fv/L/IhWnyCHaFJ3H1QPOH6A93whlQ2vG5nHlBDvzWQ==",
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Memory": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.3",
|
||||
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
|
||||
},
|
||||
"System.Numerics.Vectors": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
"contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ=="
|
||||
},
|
||||
"System.Reflection": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "JCKANJ0TI7kzoQzuwB/OoJANy1Lg338B6+JVacPl4TpUwi3cReg3nMLplMq2uqYfHFQpKIlHAUVAJlImZz/4ng==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.IO": "4.1.0",
|
||||
"System.Reflection.Primitives": "4.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Reflection.Primitives": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.1",
|
||||
"contentHash": "4inTox4wTBaDhB7V3mPvp9XlCbeGYWVEM9/fXALd52vNEAVisc1BoVWQPuUuD0Ga//dNbA/WeMy9u9mzLxGTHQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Resources.ResourceManager": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.1",
|
||||
"contentHash": "TxwVeUNoTgUOdQ09gfTjvW411MF+w9MBYL7AtNVc+HtBCFlutPLhUCdZjNkjbhj3bNQWMdHboF0KIWEOjJssbA==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Globalization": "4.0.11",
|
||||
"System.Reflection": "4.1.0",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "v6c/4Yaa9uWsq+JMhnOFewrYkgdNHNG2eMKuNqRn8P733rNXeRCGvV5FkkjBXn2dbVkPXOsO0xjsEeM1q2zC0g==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "CUOHjTT/vgP0qGW22U4/hDlOqXmcPq5YicBaXdUR2UiUoLwBT+olO6we4DVbq57jeX5uXH2uerVZhf0qGj+sVQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.Handles": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.1",
|
||||
"contentHash": "nCJvEKguXEvk2ymk1gqj625vVnlK3/xdGzx0vOKicQkoquaTBJTP13AIYkocSUwHCLNBwUbXTqTWGDxBTWpt7g==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Runtime.InteropServices": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.1.0",
|
||||
"contentHash": "16eu3kjHS633yYdkjwShDHZLRNMKVi/s0bY8ODiqJ2RfMhDMAwxZaUaWVnZ2P71kr/or+X9o/xFWtNqz8ivieQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Reflection": "4.1.0",
|
||||
"System.Reflection.Primitives": "4.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Runtime.Handles": "4.0.1"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.11",
|
||||
"contentHash": "U3gGeMlDZXxCEiY4DwVLSacg+DFWCvoiX+JThA/rvw37Sqrku7sEFeVBBBMBnfB6FeZHsyDx85HlKL19x0HtZA==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Text.Encoding.Extensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.11",
|
||||
"contentHash": "jtbiTDtvfLYgXn8PTfWI+SiBs51rrmO4AAckx4KR6vFK9Wzf6tI8kcRdsYQNwriUeQ1+CtQbM1W4cMbLXnj/OQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Text.Encoding": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.Threading": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.11",
|
||||
"contentHash": "N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==",
|
||||
"dependencies": {
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Threading.Tasks": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.Threading.Tasks": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.11",
|
||||
"contentHash": "k1S4Gc6IGwtHGT8188RSeGaX86Qw/wnrgNLshJvsdNUOPP9etMmo8S07c+UlOAx4K/xLuN9ivA1bD0LVurtIxQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Timer": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.1",
|
||||
"contentHash": "saGfUV8uqVW6LeURiqxcGhZ24PzuRNaUBtbhVeuUAvky1naH395A/1nY0P2bWvrw/BreRtIB/EzTDkGBpqCwEw==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1",
|
||||
"Microsoft.NETCore.Targets": "1.0.1",
|
||||
"System.Runtime": "4.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Tests.fs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\src\Oceanbox.FvcomKit.fsproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Expecto" Version="9.0.4" />
|
||||
<PackageReference Update="FSharp.Core" Version="6.0.4-beta.22181.2" />
|
||||
</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