Compare commits
120 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 |
@@ -18,7 +18,7 @@ let versionFile = Path.getFullName ".version"
|
||||
Target.create "Clean" (fun _ -> Shell.cleanDir distPath)
|
||||
|
||||
Target.create "InstallClient" (fun _ ->
|
||||
run npm "install" "."
|
||||
run bun "install" "."
|
||||
run dotnet "tool restore" "."
|
||||
)
|
||||
|
||||
|
||||
@@ -72,16 +72,16 @@ let createProcess exe arg dir =
|
||||
|> CreateProcess.ensureExitCode
|
||||
|
||||
let dotnet = createProcess "dotnet"
|
||||
let npm =
|
||||
let npmPath =
|
||||
match ProcessUtils.tryFindFileOnPath "npm" with
|
||||
let bun =
|
||||
let bunPath =
|
||||
match ProcessUtils.tryFindFileOnPath "bun" with
|
||||
| Some path -> path
|
||||
| None ->
|
||||
"npm was not found in path. Please install it and make sure it's available from your path. " +
|
||||
"bun was not found in path. Please install it and make sure it's available from your path. " +
|
||||
"See https://safe-stack.github.io/docs/quickstart/#install-pre-requisites for more info"
|
||||
|> failwith
|
||||
|
||||
createProcess npmPath
|
||||
createProcess bunPath
|
||||
|
||||
let run proc arg dir =
|
||||
proc arg dir
|
||||
|
||||
@@ -1,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,10 +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: .
|
||||
|
||||
7
.gitmodules
vendored
7
.gitmodules
vendored
@@ -1,7 +0,0 @@
|
||||
[submodule "submodules/ProjNet.FSharp"]
|
||||
path = submodules/ProjNet.FSharp
|
||||
url = ../ProjNet.FSharp
|
||||
[submodule "submodules/FsKdTree"]
|
||||
path = submodules/FsKdTree
|
||||
url = https://gitlab.com/serit/libs/FsKDTree.git
|
||||
shallow = true
|
||||
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.23.0" />
|
||||
<PackageReference Include="Fake.DotNet.Cli" Version="5.23.0" />
|
||||
<PackageReference Include="Fake.IO.FileSystem" Version="5.23.0" />
|
||||
<PackageReference Include="Farmer" Version="1.7.10" />
|
||||
<PackageReference Update="FSharp.Core" Version="6.0.5" />
|
||||
<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>
|
||||
232
RELEASE_NOTES.md
232
RELEASE_NOTES.md
@@ -1,5 +1,237 @@
|
||||
# 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)
|
||||
|
||||
|
||||
|
||||
302
bun.lock
Normal file
302
bun.lock
Normal file
@@ -0,0 +1,302 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 0,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@semantic-release/changelog": "^6.0.1",
|
||||
"@semantic-release/exec": "^6.0.3",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@semantic-release/gitlab": "^7.0.4",
|
||||
"semantic-release-dotnet": "^1.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@babel/code-frame": ["@babel/code-frame@7.16.7", "", { "dependencies": { "@babel/highlight": "^7.16.7" } }, "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.16.7", "", {}, "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="],
|
||||
|
||||
"@babel/highlight": ["@babel/highlight@7.16.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||
|
||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||
|
||||
"@semantic-release/changelog": ["@semantic-release/changelog@6.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "fs-extra": "^9.0.0", "lodash": "^4.17.4" } }, "sha512-FT+tAGdWHr0RCM3EpWegWnvXJ05LQtBkQUaQRIExONoXjVjLuOILNm4DEKNaV+GAQyJjbLRVs57ti//GypH6PA=="],
|
||||
|
||||
"@semantic-release/error": ["@semantic-release/error@3.0.0", "", {}, "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw=="],
|
||||
|
||||
"@semantic-release/exec": ["@semantic-release/exec@6.0.3", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "parse-json": "^5.0.0" } }, "sha512-bxAq8vLOw76aV89vxxICecEa8jfaWwYITw6X74zzlO0mc/Bgieqx9kBRz9z96pHectiTAtsCwsQcUyLYWnp3VQ=="],
|
||||
|
||||
"@semantic-release/git": ["@semantic-release/git@10.0.1", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", "execa": "^5.0.0", "lodash": "^4.17.4", "micromatch": "^4.0.0", "p-reduce": "^2.0.0" } }, "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w=="],
|
||||
|
||||
"@semantic-release/gitlab": ["@semantic-release/gitlab@7.0.4", "", { "dependencies": { "@semantic-release/error": "^3.0.0", "aggregate-error": "^3.0.0", "debug": "^4.0.0", "dir-glob": "^3.0.0", "escape-string-regexp": "^3.0.0", "form-data": "^4.0.0", "fs-extra": "^10.0.0", "globby": "^11.0.0", "got": "^11.0.0", "lodash": "^4.17.11", "parse-path": "^4.0.0", "url-join": "^4.0.0" } }, "sha512-TL6kT526+ir/uehMFdTlJNXUj+p+SjPAYUkit6lh5Rs8kxeHQ01bgmpYLQlc94ZDpy9x2Tzcb/NRwKojkmLG4A=="],
|
||||
|
||||
"@sindresorhus/is": ["@sindresorhus/is@4.3.0", "", {}, "sha512-wwOvh0eO3PiTEivGJWiZ+b946SlMSb4pe+y+Ur/4S87cwo09pYi+FWHHnbrM3W9W7cBYKDqQXcrFYjYUCOJUEQ=="],
|
||||
|
||||
"@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="],
|
||||
|
||||
"@types/cacheable-request": ["@types/cacheable-request@6.0.2", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "*", "@types/node": "*", "@types/responselike": "*" } }, "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA=="],
|
||||
|
||||
"@types/glob": ["@types/glob@7.2.0", "", { "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA=="],
|
||||
|
||||
"@types/http-cache-semantics": ["@types/http-cache-semantics@4.0.1", "", {}, "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="],
|
||||
|
||||
"@types/keyv": ["@types/keyv@3.1.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg=="],
|
||||
|
||||
"@types/minimatch": ["@types/minimatch@3.0.5", "", {}, "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="],
|
||||
|
||||
"@types/node": ["@types/node@17.0.9", "", {}, "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ=="],
|
||||
|
||||
"@types/responselike": ["@types/responselike@1.0.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA=="],
|
||||
|
||||
"aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="],
|
||||
|
||||
"array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="],
|
||||
|
||||
"asynckit": ["asynckit@0.4.0", "", {}, "sha1-x57Zf380y48robyXkLzDZkdLS3k="],
|
||||
|
||||
"at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
|
||||
|
||||
"braces": ["braces@3.0.2", "", { "dependencies": { "fill-range": "^7.0.1" } }, "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="],
|
||||
|
||||
"cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="],
|
||||
|
||||
"cacheable-request": ["cacheable-request@7.0.2", "", { "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew=="],
|
||||
|
||||
"call-bind": ["call-bind@1.0.2", "", { "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" } }, "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="],
|
||||
|
||||
"chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="],
|
||||
|
||||
"clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="],
|
||||
|
||||
"clone-response": ["clone-response@1.0.2", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws="],
|
||||
|
||||
"color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="],
|
||||
|
||||
"color-name": ["color-name@1.1.3", "", {}, "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="],
|
||||
|
||||
"combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="],
|
||||
|
||||
"debug": ["debug@4.3.3", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q=="],
|
||||
|
||||
"decode-uri-component": ["decode-uri-component@0.2.0", "", {}, "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="],
|
||||
|
||||
"decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="],
|
||||
|
||||
"defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="],
|
||||
|
||||
"delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="],
|
||||
|
||||
"dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="],
|
||||
|
||||
"end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="],
|
||||
|
||||
"error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@3.0.0", "", {}, "sha512-11dXIUC3umvzEViLP117d0KN6LJzZxh5+9F4E/7WLAAw7GrHk8NpUR+g9iJi/pe9C0py4F8rs0hreyRCwlAuZg=="],
|
||||
|
||||
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||
|
||||
"fast-glob": ["fast-glob@3.2.11", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew=="],
|
||||
|
||||
"fastq": ["fastq@1.13.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw=="],
|
||||
|
||||
"fill-range": ["fill-range@7.0.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="],
|
||||
|
||||
"filter-obj": ["filter-obj@1.1.0", "", {}, "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="],
|
||||
|
||||
"form-data": ["form-data@4.0.0", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww=="],
|
||||
|
||||
"fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="],
|
||||
|
||||
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="],
|
||||
|
||||
"function-bind": ["function-bind@1.1.1", "", {}, "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="],
|
||||
|
||||
"get-intrinsic": ["get-intrinsic@1.1.1", "", { "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1" } }, "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q=="],
|
||||
|
||||
"get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="],
|
||||
|
||||
"glob": ["glob@7.2.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q=="],
|
||||
|
||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"glob-promise": ["glob-promise@4.2.2", "", { "dependencies": { "@types/glob": "^7.1.3" }, "peerDependencies": { "glob": "^7.1.6" } }, "sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw=="],
|
||||
|
||||
"globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
|
||||
|
||||
"got": ["got@11.8.3", "", { "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", "p-cancelable": "^2.0.0", "responselike": "^2.0.0" } }, "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.9", "", {}, "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="],
|
||||
|
||||
"has": ["has@1.0.3", "", { "dependencies": { "function-bind": "^1.1.1" } }, "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="],
|
||||
|
||||
"has-flag": ["has-flag@3.0.0", "", {}, "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="],
|
||||
|
||||
"has-symbols": ["has-symbols@1.0.2", "", {}, "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="],
|
||||
|
||||
"http-cache-semantics": ["http-cache-semantics@4.1.0", "", {}, "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ=="],
|
||||
|
||||
"http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="],
|
||||
|
||||
"human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
|
||||
|
||||
"ignore": ["ignore@5.2.0", "", {}, "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="],
|
||||
|
||||
"indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="],
|
||||
|
||||
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-ssh": ["is-ssh@1.3.3", "", { "dependencies": { "protocols": "^1.1.0" } }, "sha512-NKzJmQzJfEEma3w5cJNcUMxoXfDjz0Zj0eyCalHn2E6VOwlzjZo0yuO2fcBSf8zhFuVCL/82/r5gRcoi6aEPVQ=="],
|
||||
|
||||
"is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||
|
||||
"json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="],
|
||||
|
||||
"jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="],
|
||||
|
||||
"keyv": ["keyv@4.0.5", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-531pkGLqV3BMg0eDqqJFI0R1mkK1Nm5xIP2mM6keP5P8WfFtCkg2IOwplTUmlGoTgIg9yQYZ/kdihhz89XH3vA=="],
|
||||
|
||||
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||
|
||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="],
|
||||
|
||||
"merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="],
|
||||
|
||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||
|
||||
"micromatch": ["micromatch@4.0.4", "", { "dependencies": { "braces": "^3.0.1", "picomatch": "^2.2.3" } }, "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg=="],
|
||||
|
||||
"mime-db": ["mime-db@1.51.0", "", {}, "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="],
|
||||
|
||||
"mime-types": ["mime-types@2.1.34", "", { "dependencies": { "mime-db": "1.51.0" } }, "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A=="],
|
||||
|
||||
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
||||
|
||||
"mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="],
|
||||
|
||||
"minimatch": ["minimatch@3.0.4", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA=="],
|
||||
|
||||
"ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="],
|
||||
|
||||
"normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="],
|
||||
|
||||
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"object-inspect": ["object-inspect@1.12.0", "", {}, "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha1-WDsap3WWHUsROsF9nFC6753Xa9E="],
|
||||
|
||||
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
||||
|
||||
"p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="],
|
||||
|
||||
"p-reduce": ["p-reduce@2.1.0", "", {}, "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw=="],
|
||||
|
||||
"parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="],
|
||||
|
||||
"parse-path": ["parse-path@4.0.3", "", { "dependencies": { "is-ssh": "^1.3.0", "protocols": "^1.4.0", "qs": "^6.9.4", "query-string": "^6.13.8" } }, "sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA=="],
|
||||
|
||||
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="],
|
||||
|
||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"protocols": ["protocols@1.4.8", "", {}, "sha512-IgjKyaUSjsROSO8/D49Ab7hP8mJgTYcqApOqdPhLoPxAplXmkp+zRvsrSQjFn5by0rhm4VH0GAUELIPpx7B1yg=="],
|
||||
|
||||
"pump": ["pump@3.0.0", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww=="],
|
||||
|
||||
"qs": ["qs@6.10.3", "", { "dependencies": { "side-channel": "^1.0.4" } }, "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ=="],
|
||||
|
||||
"query-string": ["query-string@6.14.1", "", { "dependencies": { "decode-uri-component": "^0.2.0", "filter-obj": "^1.1.0", "split-on-first": "^1.0.0", "strict-uri-encode": "^2.0.0" } }, "sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw=="],
|
||||
|
||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||
|
||||
"quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="],
|
||||
|
||||
"resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="],
|
||||
|
||||
"responselike": ["responselike@2.0.0", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw=="],
|
||||
|
||||
"reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
"sax": ["sax@1.2.4", "", {}, "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="],
|
||||
|
||||
"semantic-release-dotnet": ["semantic-release-dotnet@1.0.0", "", { "dependencies": { "glob": "^7.1.7", "glob-promise": "^4.2.0", "xml-js": "^1.6.11" } }, "sha512-U/cHwqqzFbJpPCQ/KMTSZtwzPNWCNCVStZRznMGK0xjhiLoDfRe5KFRs/9dzWBtPa358D7IiVzz97ZzepUAtfQ=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"side-channel": ["side-channel@1.0.4", "", { "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", "object-inspect": "^1.9.0" } }, "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw=="],
|
||||
|
||||
"signal-exit": ["signal-exit@3.0.6", "", {}, "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="],
|
||||
|
||||
"slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
|
||||
|
||||
"split-on-first": ["split-on-first@1.1.0", "", {}, "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="],
|
||||
|
||||
"strict-uri-encode": ["strict-uri-encode@2.0.0", "", {}, "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="],
|
||||
|
||||
"strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="],
|
||||
|
||||
"supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"universalify": ["universalify@2.0.0", "", {}, "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="],
|
||||
|
||||
"url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="],
|
||||
|
||||
"xml-js": ["xml-js@1.6.11", "", { "dependencies": { "sax": "^1.2.4" }, "bin": "bin/cli.js" }, "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g=="],
|
||||
|
||||
"@semantic-release/gitlab/fs-extra": ["fs-extra@10.0.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ=="],
|
||||
|
||||
"cacheable-request/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
||||
|
||||
"chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="],
|
||||
|
||||
"clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="],
|
||||
}
|
||||
}
|
||||
19
default.nix
Normal file
19
default.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
sources ? import ./nix,
|
||||
system ? builtins.currentSystem,
|
||||
pkgs ? import sources.nixpkgs {
|
||||
inherit system;
|
||||
config = { };
|
||||
overlays = [ ];
|
||||
},
|
||||
}:
|
||||
let
|
||||
sdk = pkgs.dotnetCorePackages.sdk_9_0;
|
||||
sdslite = pkgs.callPackage ./nix/sdslite.nix { dotnet-sdk = sdk; };
|
||||
projnetFsharp = pkgs.callPackage ./nix/projnet.fsharp.nix { dotnet-sdk = sdk; };
|
||||
in
|
||||
pkgs.callPackage ./src {
|
||||
SDSLite = sdslite;
|
||||
projnet = projnetFsharp;
|
||||
dotnet-sdk = sdk;
|
||||
}
|
||||
146
nix/default.nix
Normal file
146
nix/default.nix
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
This file is provided under the MIT licence:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
# Generated by npins. Do not modify; will be overwritten regularly
|
||||
let
|
||||
data = builtins.fromJSON (builtins.readFile ./sources.json);
|
||||
version = data.version;
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
|
||||
range =
|
||||
first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
|
||||
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
|
||||
|
||||
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
|
||||
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
|
||||
concatMapStrings = f: list: concatStrings (map f list);
|
||||
concatStrings = builtins.concatStringsSep "";
|
||||
|
||||
# If the environment variable NPINS_OVERRIDE_${name} is set, then use
|
||||
# the path directly as opposed to the fetched source.
|
||||
# (Taken from Niv for compatibility)
|
||||
mayOverride =
|
||||
name: path:
|
||||
let
|
||||
envVarName = "NPINS_OVERRIDE_${saneName}";
|
||||
saneName = stringAsChars (c: if (builtins.match "[a-zA-Z0-9]" c) == null then "_" else c) name;
|
||||
ersatz = builtins.getEnv envVarName;
|
||||
in
|
||||
if ersatz == "" then
|
||||
path
|
||||
else
|
||||
# this turns the string into an actual Nix path (for both absolute and
|
||||
# relative paths)
|
||||
builtins.trace "Overriding path of \"${name}\" with \"${ersatz}\" due to set \"${envVarName}\"" (
|
||||
if builtins.substring 0 1 ersatz == "/" then
|
||||
/. + ersatz
|
||||
else
|
||||
/. + builtins.getEnv "PWD" + "/${ersatz}"
|
||||
);
|
||||
|
||||
mkSource =
|
||||
name: spec:
|
||||
assert spec ? type;
|
||||
let
|
||||
path =
|
||||
if spec.type == "Git" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "GitRelease" then
|
||||
mkGitSource spec
|
||||
else if spec.type == "PyPi" then
|
||||
mkPyPiSource spec
|
||||
else if spec.type == "Channel" then
|
||||
mkChannelSource spec
|
||||
else if spec.type == "Tarball" then
|
||||
mkTarballSource spec
|
||||
else
|
||||
builtins.throw "Unknown source type ${spec.type}";
|
||||
in
|
||||
spec // { outPath = mayOverride name path; };
|
||||
|
||||
mkGitSource =
|
||||
{
|
||||
repository,
|
||||
revision,
|
||||
url ? null,
|
||||
submodules,
|
||||
hash,
|
||||
branch ? null,
|
||||
...
|
||||
}:
|
||||
assert repository ? type;
|
||||
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
|
||||
# In the latter case, there we will always be an url to the tarball
|
||||
if url != null && !submodules then
|
||||
builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash; # FIXME: check nix version & use SRI hashes
|
||||
}
|
||||
else
|
||||
let
|
||||
url =
|
||||
if repository.type == "Git" then
|
||||
repository.url
|
||||
else if repository.type == "GitHub" then
|
||||
"https://github.com/${repository.owner}/${repository.repo}.git"
|
||||
else if repository.type == "GitLab" then
|
||||
"${repository.server}/${repository.repo_path}.git"
|
||||
else
|
||||
throw "Unrecognized repository type ${repository.type}";
|
||||
urlToName =
|
||||
url: rev:
|
||||
let
|
||||
matched = builtins.match "^.*/([^/]*)(\\.git)?$" url;
|
||||
|
||||
short = builtins.substring 0 7 rev;
|
||||
|
||||
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
|
||||
in
|
||||
"${if matched == null then "source" else builtins.head matched}${appendShort}";
|
||||
name = urlToName url revision;
|
||||
in
|
||||
builtins.fetchGit {
|
||||
rev = revision;
|
||||
inherit name;
|
||||
# hash = hash;
|
||||
inherit url submodules;
|
||||
};
|
||||
|
||||
mkPyPiSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchurl {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkChannelSource =
|
||||
{ url, hash, ... }:
|
||||
builtins.fetchTarball {
|
||||
inherit url;
|
||||
sha256 = hash;
|
||||
};
|
||||
|
||||
mkTarballSource =
|
||||
{
|
||||
url,
|
||||
locked_url ? url,
|
||||
hash,
|
||||
...
|
||||
}:
|
||||
builtins.fetchTarball {
|
||||
url = locked_url;
|
||||
sha256 = hash;
|
||||
};
|
||||
in
|
||||
if version == 5 then
|
||||
builtins.mapAttrs mkSource data.pins
|
||||
else
|
||||
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"
|
||||
29
nix/projnet.fsharp.nix
Normal file
29
nix/projnet.fsharp.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
dotnet-sdk,
|
||||
fetchFromGitLab,
|
||||
buildDotnetModule
|
||||
}:
|
||||
let
|
||||
src = fetchFromGitLab {
|
||||
owner = "oceanbox";
|
||||
repo = "ProjNet.FSharp";
|
||||
# tag = "v5.2.0";
|
||||
rev = "722ce0c23fda6844a81e995afbb2d81cbd5f38ec";
|
||||
private = true;
|
||||
forceFetchGit = true;
|
||||
hash = "sha256-Rvnnf/D2x90pwgvTbXz307MJVBlVPK/cCf1hqj2VosE=";
|
||||
};
|
||||
in
|
||||
buildDotnetModule {
|
||||
name = "ProjNet.FSharp";
|
||||
|
||||
src = src;
|
||||
|
||||
dotnet-sdk = dotnet-sdk;
|
||||
|
||||
projectFile = "src/ProjNet.FSharp.fsproj";
|
||||
nugetDeps = "${src}/src/deps.json";
|
||||
packNupkg = true;
|
||||
|
||||
executables = [ ];
|
||||
}
|
||||
29
nix/sdslite.nix
Normal file
29
nix/sdslite.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
dotnet-sdk,
|
||||
fetchFromGitLab,
|
||||
buildDotnetModule
|
||||
}:
|
||||
let
|
||||
src = fetchFromGitLab {
|
||||
owner = "oceanbox";
|
||||
repo = "SDSlite";
|
||||
# tag = "v2.8.0";
|
||||
rev = "8c1a158206c37bc57a5bd726a792bd6a9cd2ec01";
|
||||
private = true;
|
||||
forceFetchGit = true;
|
||||
hash = "sha256-i9pNrmH/VC0Q9FCldbWGdZHkqSL1cdYtAOs7vX+DlXM=";
|
||||
};
|
||||
in
|
||||
buildDotnetModule {
|
||||
name = "Oceanbox.SDSLite";
|
||||
|
||||
src = src;
|
||||
|
||||
dotnet-sdk = dotnet-sdk;
|
||||
|
||||
projectFile = "ScientificDataSet/ScientificDataSet.csproj";
|
||||
nugetDeps = "${src}/ScientificDataSet/deps.json";
|
||||
packNupkg = true;
|
||||
|
||||
executables = [ ];
|
||||
}
|
||||
23
nix/sources.json
Normal file
23
nix/sources.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"pins": {
|
||||
"nix-utils": {
|
||||
"type": "Git",
|
||||
"repository": {
|
||||
"type": "Git",
|
||||
"url": "https://git.sr.ht/~mrtz/nix-utils"
|
||||
},
|
||||
"branch": "trunk",
|
||||
"submodules": false,
|
||||
"revision": "098f594425d2b9dde0657becad0f6498d074f8b3",
|
||||
"url": null,
|
||||
"hash": "0hh52w1fkpr1xx6j8cjm6g88j2352yv2ysqm1q51j59y6f583vyb"
|
||||
},
|
||||
"nixpkgs": {
|
||||
"type": "Channel",
|
||||
"name": "nixpkgs-unstable",
|
||||
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre905319.f720de590661/nixexprs.tar.xz",
|
||||
"hash": "07n4hhch0j6n69b0zchdjg0l80z2xrdk7k57ykv90cvhklim5dz1"
|
||||
}
|
||||
},
|
||||
"version": 5
|
||||
}
|
||||
4
nix/sources.nix
Normal file
4
nix/sources.nix
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"ProjNet.FSharp" = "https://gitlab.com/api/v4/projects/35009572/packages/nuget/download";
|
||||
"Oceanbox.SDSLite" = "https://gitlab.com/api/v4/projects/34025102/packages/nuget/download";
|
||||
}
|
||||
2772
package-lock.json
generated
2772
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
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;
|
||||
}
|
||||
236
src/Adjoin.fs
236
src/Adjoin.fs
@@ -1,7 +1,7 @@
|
||||
module Oceanbox.FvcomKit.Adjoin
|
||||
|
||||
open FSharpPlus
|
||||
open FsKDTree
|
||||
//open FsKDTree
|
||||
open ProjNet.FSharp
|
||||
open Grid
|
||||
open Types
|
||||
@@ -9,10 +9,10 @@ open Polygon
|
||||
open KdTree // C# version
|
||||
|
||||
type CropBox = (float * float) * (float * float)
|
||||
type Mask = bool [,]
|
||||
type Mask = bool[,]
|
||||
type Pos = float * float
|
||||
type PosVec = Pos []
|
||||
type BiPos = float [,] * float [,]
|
||||
type PosVec = Pos[]
|
||||
type BiPos = float[,] * float[,]
|
||||
|
||||
let private reProject (proj: IProj) ((lng, lat): BiPos) =
|
||||
lng
|
||||
@@ -20,7 +20,7 @@ let private reProject (proj: IProj) ((lng, lat): BiPos) =
|
||||
|> Array2D.map proj.project
|
||||
|> unzip2D
|
||||
|
||||
let private genCropIdx ((min, max): float * float) (m: float [,]) =
|
||||
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
|
||||
@@ -44,22 +44,21 @@ let private mkCropBox (box: BBox) : CropBox =
|
||||
|
||||
// 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])
|
||||
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 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<float, int> []) =
|
||||
let tree = KdTree<float, int>(2, KdTree.Math.DoubleMath())
|
||||
let private createTree (points: Leaf<int>[]) =
|
||||
let tree = KdTree<float, int> (2, KdTree.Math.DoubleMath ())
|
||||
points
|
||||
|> Array.iter (fun a -> tree.Add([| a.Pos.X; a.Pos.Y |], a.Data) |> ignore)
|
||||
|> Array.iter (fun a -> tree.Add ([| fst a.Pos; snd a.Pos |], a.Data) |> ignore)
|
||||
if points.Length > 0 then
|
||||
tree.Balance()
|
||||
tree.Balance ()
|
||||
else
|
||||
// Log.Warning $"Empty kd-tree"
|
||||
()
|
||||
@@ -68,14 +67,14 @@ let private createTree (points: Leaf<float, int> []) =
|
||||
// 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 = x; Y = y }; Data = n })
|
||||
|> 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 [] }
|
||||
type FvcomAdjoint = { adjoinIdx: int[]; cullIdx: (int * int)[]; oobIdx: int[] }
|
||||
|
||||
let private dist (a: float * float) (b: float * float) =
|
||||
let x0, y0 = a
|
||||
@@ -107,14 +106,13 @@ let private distLngLat (proj: IProj) (a: float * float) (b: float * float) =
|
||||
// (0, [])
|
||||
// |> snd
|
||||
// |> Array.ofList
|
||||
let private genOobIdx (proj: IProj) (tree: KdTree<_, _>) (cullIdx: (int * int) []) (fPos: PosVec) (rPos: BiPos) =
|
||||
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])
|
||||
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)
|
||||
tree.GetNearestNeighbours ([| x; y |], 1)
|
||||
|> Array.head
|
||||
|> fun p ->
|
||||
let i0, i1 = cullIdx[p.Value]
|
||||
@@ -141,6 +139,7 @@ let private genOobIdx (proj: IProj) (tree: KdTree<_, _>) (cullIdx: (int * int) [
|
||||
// cullIdx = cullIdx
|
||||
// oobIdx = genOobIdx proj tree cullIdx fPos rPos
|
||||
// }
|
||||
|
||||
let private mkFvcomAdjoint (proj: IProj) (fPos: PosVec) (bbox: BBox) ((rPos, wet): BiPos * Mask) =
|
||||
let box = mkCropBox bbox
|
||||
let pos' = reProject proj rPos
|
||||
@@ -148,15 +147,10 @@ let private mkFvcomAdjoint (proj: IProj) (fPos: PosVec) (bbox: BBox) ((rPos, wet
|
||||
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)
|
||||
{
|
||||
adjoinIdx = nearest
|
||||
cullIdx = cullIdx
|
||||
oobIdx = genOobIdx proj tree cullIdx fPos rPos
|
||||
}
|
||||
|> 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
|
||||
|
||||
@@ -169,26 +163,26 @@ 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<float, int * int> []) =
|
||||
let tree = KdTree<float, int * int>(2, KdTree.Math.DoubleMath())
|
||||
let private createIdxTree (points: Leaf<int * int>[]) =
|
||||
let tree = KdTree<float, int * int> (2, KdTree.Math.DoubleMath ())
|
||||
points
|
||||
|> Array.iter (fun a -> tree.Add([| a.Pos.X; a.Pos.Y |], a.Data) |> ignore)
|
||||
|> Array.iter (fun a -> tree.Add ([| fst a.Pos; snd a.Pos |], a.Data) |> ignore)
|
||||
if points.Length > 0 then
|
||||
tree.Balance()
|
||||
tree.Balance ()
|
||||
else
|
||||
//Log.Warning $"Empty kd-tree"
|
||||
()
|
||||
tree
|
||||
|
||||
// rPos must be in the right projection!
|
||||
let makeNestTree ((lng, lat): float [,] * float [,]) =
|
||||
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 = x; Y = y }; Data = (i, j) }))
|
||||
{ Pos = x, y; Data = (i, j) }))
|
||||
|> Array.concat
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createIdxTree
|
||||
@@ -196,36 +190,31 @@ let makeNestTree ((lng, lat): float [,] * float [,]) =
|
||||
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
|
||||
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 |]
|
||||
@@ -237,85 +226,84 @@ let getNearestUpperLeft' (tree: KdTree<float, int * int>) (((ew, ns), mask): BiP
|
||||
[| 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
|
||||
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 getNearestUpperLeft
|
||||
(tree: Tree<Leaf<float, int * int> array, 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
|
||||
// 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 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) []) =
|
||||
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) =
|
||||
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 [,]) =
|
||||
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 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
|
||||
623
src/Fvcom.fs
623
src/Fvcom.fs
@@ -2,329 +2,474 @@ module Oceanbox.FvcomKit.Fvcom
|
||||
|
||||
#nowarn "57"
|
||||
|
||||
open System
|
||||
open Microsoft.Research.Science.Data
|
||||
open FSharpPlus
|
||||
open ProjNet.FSharp
|
||||
open Serilog
|
||||
open Grid
|
||||
|
||||
type FvcomGrid =
|
||||
{
|
||||
Elem: Elem array
|
||||
Nodes: Node array
|
||||
BBox: BBox
|
||||
Cells: Node array
|
||||
Bathymetry: single []
|
||||
Siglay: single [,]
|
||||
SiglayCenter: single [,]
|
||||
Siglev: single [,]
|
||||
Proj: Projection
|
||||
}
|
||||
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 x.getVertex n = x.Nodes[n]
|
||||
member x.getCell n = x.Elem[n]
|
||||
member x.getCellVertices n =
|
||||
let a, b, c = x.Elem[n]
|
||||
x.Nodes[a], x.Nodes[b], x.Nodes[c]
|
||||
member x.getVertices() = x.Nodes
|
||||
member x.getCells() = x.Elem
|
||||
member x.getBoundingBox() = x.BBox
|
||||
member x.Projection = x.Proj
|
||||
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
|
||||
Proj = WebMercator
|
||||
}
|
||||
member this.ToGrid() =
|
||||
{
|
||||
Elem = this.Elem
|
||||
Nodes = this.Nodes
|
||||
BBox = this.BBox
|
||||
Proj = this.Proj
|
||||
}
|
||||
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 ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
0
|
||||
|
||||
let getNumSiglay (ds: DataSet) =
|
||||
try
|
||||
ds.Dimensions["siglay"].Length
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
0
|
||||
|
||||
let getNumSiglev (ds: DataSet) =
|
||||
try
|
||||
ds.Dimensions["siglev"].Length
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
0
|
||||
|
||||
let getTime (ds: DataSet) n =
|
||||
try
|
||||
let ts = ds[ "Times" ].GetData() :?> byte [,]
|
||||
let ts = ds["Times"].GetData () :?> byte[,]
|
||||
|
||||
ts[n, *]
|
||||
|> Array.map char
|
||||
|> System.String
|
||||
|> System.DateTime.Parse
|
||||
|> Some
|
||||
with
|
||||
| e ->
|
||||
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 = 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 ->
|
||||
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 [,,]
|
||||
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 ->
|
||||
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 [,,]
|
||||
let ww = ds["ww"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
ww[0, 0, *]
|
||||
with
|
||||
| e ->
|
||||
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 [,,]
|
||||
let ww = ds["ww"].GetData ([| t; l; 0 |], [| 1; 1; n |]) :?> single[,,]
|
||||
es |> Array.map (fun i -> ww[0, 0, i])
|
||||
with
|
||||
| e ->
|
||||
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 [,,]
|
||||
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 ->
|
||||
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 = 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 ->
|
||||
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 [,,]
|
||||
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 ->
|
||||
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 [,]
|
||||
let zeta = ds["zeta"].GetData ([| t; 0 |], [| 1; n |]) :?> single[,]
|
||||
zeta[0, *]
|
||||
with
|
||||
| e ->
|
||||
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
|
||||
ds[ "h_center" ].GetData() :?> single []
|
||||
with
|
||||
| e ->
|
||||
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 l = ds.Dimensions["siglev"].Length
|
||||
let siglev = ds[ "siglev" ].GetData([| 0; n |], [| l; 1 |]) :?> single [,]
|
||||
let siglev = ds["siglev"].GetData ([| 0; n |], [| l; 1 |]) :?> single[,]
|
||||
siglev[*, 0]
|
||||
with
|
||||
| err ->
|
||||
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 l = ds.Dimensions["siglay"].Length
|
||||
let siglay = ds[ "siglay" ].GetData([| 0; n |], [| l; 1 |]) :?> single [,]
|
||||
let siglay = ds["siglay"].GetData ([| 0; n |], [| l; 1 |]) :?> single[,]
|
||||
siglay[*, 0]
|
||||
with
|
||||
| err ->
|
||||
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 l = ds.Dimensions["siglev"].Length
|
||||
let siglev =
|
||||
ds["siglev_center"]
|
||||
.GetData([| 0; e |], [| l; 1 |])
|
||||
:?> single [,]
|
||||
siglev[*, 0]
|
||||
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 l = ds.Dimensions["siglay"].Length
|
||||
let siglay =
|
||||
ds["siglay_center"]
|
||||
.GetData([| 0; e |], [| l; 1 |])
|
||||
:?> single [,]
|
||||
siglay[*, 0]
|
||||
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
|
||||
@@ -332,12 +477,11 @@ module Siglay =
|
||||
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 [,,]
|
||||
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 ->
|
||||
with err ->
|
||||
Log.Warning $"readUv {e} {t}"
|
||||
Log.Error $"{err}"
|
||||
Array.empty
|
||||
@@ -345,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
|
||||
@@ -358,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
|
||||
@@ -369,27 +510,59 @@ 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 =
|
||||
float (minX + (maxX - minX)) / 2., float (minY + (maxY - minY)) / 2.
|
||||
let center = float (minX + maxX) / 2., float (minY + maxY) / 2.
|
||||
{
|
||||
minX = float minX
|
||||
maxX = float maxX
|
||||
@@ -397,41 +570,40 @@ let getBBox (ds: DataSet) : BBox =
|
||||
maxY = float maxY
|
||||
center = center
|
||||
}
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
BBox.empty
|
||||
|
||||
let getGrid (ds: DataSet) : FvcomGrid =
|
||||
try
|
||||
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 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)
|
||||
let nds = Array.zip x y
|
||||
let cells = Array.zip xc yc
|
||||
let proj =
|
||||
try
|
||||
ds.Metadata["CoordinateProjection"] :?> string
|
||||
with
|
||||
| _ -> ""
|
||||
{
|
||||
Elem = elem
|
||||
Nodes = nds
|
||||
@@ -441,26 +613,65 @@ let getGrid (ds: DataSet) : FvcomGrid =
|
||||
Siglay = siglay
|
||||
SiglayCenter = siglay_c
|
||||
Siglev = siglev
|
||||
Proj = Projection.FromString proj
|
||||
}
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error $"{e}"
|
||||
FvcomGrid.empty
|
||||
|
||||
let getGridLonLat (ds: DataSet) : FvcomGrid =
|
||||
try
|
||||
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 [,]
|
||||
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
|
||||
nbve[*, i] |> Array.filter ((<>) 0) |> Array.map (fun x -> x - 1) |> Array.rev
|
||||
|]
|
||||
|
||||
let projectFvcomGrid proj (grid: FvcomGrid) : FvcomGrid =
|
||||
{ grid with
|
||||
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
|
||||
}
|
||||
}
|
||||
536
src/Grid.fs
536
src/Grid.fs
@@ -6,9 +6,12 @@ open FSharpPlus.Control
|
||||
open ProjNet.CoordinateSystems
|
||||
open Serilog
|
||||
open ProjNet.FSharp
|
||||
open MessagePack
|
||||
open MBrace.FsPickler
|
||||
open FsKDTree
|
||||
open KdTree // C# version
|
||||
//open FsKDTree
|
||||
open KdTree // NOTE: C# version
|
||||
|
||||
open Types
|
||||
|
||||
type NodeIdx = int
|
||||
type ElemIdx = int
|
||||
@@ -18,105 +21,75 @@ type Elem = NodeIdx * NodeIdx * NodeIdx
|
||||
type Node = float * float
|
||||
|
||||
type Pos = float * float
|
||||
type Field = (float * float) []
|
||||
|
||||
type BBox =
|
||||
{
|
||||
minX: float
|
||||
maxX: float
|
||||
minY: float
|
||||
maxY: float
|
||||
center: float * float
|
||||
}
|
||||
static member empty =
|
||||
{
|
||||
minX = Double.MaxValue
|
||||
maxX = Double.MinValue
|
||||
minY = Double.MaxValue
|
||||
maxY = Double.MinValue
|
||||
center = 0, 0
|
||||
}
|
||||
type Leaf<'a> = { Pos: Pos; Data: 'a }
|
||||
type Field = (float * float) array
|
||||
|
||||
type Cell = NodeIdx * NodeIdx * NodeIdx
|
||||
type Vertex = float * float
|
||||
|
||||
type IGrid =
|
||||
abstract getVertex: int -> Vertex
|
||||
abstract getCell: int -> Cell
|
||||
abstract getCellVertices: int -> Vertex * Vertex * Vertex
|
||||
abstract getVertices: unit -> Vertex []
|
||||
abstract getCells: unit -> Cell []
|
||||
abstract getVertices: unit -> Vertex array
|
||||
abstract getCells: unit -> Cell array
|
||||
abstract getBoundingBox: unit -> BBox
|
||||
abstract Projection: Projection
|
||||
|
||||
type Grid =
|
||||
{
|
||||
Elem: Elem array
|
||||
Nodes: Node array
|
||||
BBox: BBox
|
||||
Proj: Projection
|
||||
}
|
||||
type Grid = {
|
||||
Elem: Elem array
|
||||
Nodes: Node array
|
||||
BBox: BBox
|
||||
} with
|
||||
interface IGrid with
|
||||
member x.getVertex n = x.Nodes[n]
|
||||
member x.getCell n = x.Elem[n]
|
||||
member x.getCellVertices n =
|
||||
let a, b, c = x.Elem[n]
|
||||
x.Nodes[a], x.Nodes[b], x.Nodes[c]
|
||||
member x.getVertices() = x.Nodes
|
||||
member x.getCells() = x.Elem
|
||||
member x.getBoundingBox() = x.BBox
|
||||
member x.Projection = x.Proj
|
||||
static member empty =
|
||||
{
|
||||
Elem = Array.empty
|
||||
Nodes = Array.empty
|
||||
BBox = BBox.empty
|
||||
Proj = WebMercator
|
||||
}
|
||||
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 []>
|
||||
type NodesAroundNode = Map<NodeIdx, NodeIdx []>
|
||||
type ElemsAroundNode = Map<NodeIdx, ElemIdx array>
|
||||
type NodesAroundNode = Map<NodeIdx, NodeIdx array>
|
||||
type ElemsAroundElem = Map<ElemIdx, ElemIdx array>
|
||||
|
||||
type NeighborIndex =
|
||||
{
|
||||
ElemsAroundNode: ElemsAroundNode
|
||||
NodesAroundNode: NodesAroundNode
|
||||
}
|
||||
static member empty = { ElemsAroundNode = Map.empty; NodesAroundNode = Map.empty }
|
||||
|
||||
type private Ean = Map<NodeIdx, ElemIdx list>
|
||||
type NeighborIndex = {
|
||||
ElemsAroundNode: ElemsAroundNode
|
||||
NodesAroundNode: NodesAroundNode
|
||||
ElemsAroundElem: ElemsAroundElem
|
||||
} with
|
||||
static member empty = { ElemsAroundNode = Map.empty; NodesAroundNode = Map.empty; ElemsAroundElem = Map.empty }
|
||||
|
||||
// NOTE(SimenLK): The amount of items to be stored in the trees leafs
|
||||
let treeLeafSize = LeafNodeSize 64
|
||||
// let treeLeafSize = LeafNodeSize 64
|
||||
|
||||
let private createTree (points: Leaf<double, int> []) =
|
||||
let tree = KdTree<float, int>(2, KdTree.Math.DoubleMath())
|
||||
points
|
||||
|> Array.iter (fun a -> tree.Add([| a.Pos.X; a.Pos.Y |], a.Data) |> ignore)
|
||||
let private createTree (points: Leaf<int> array) =
|
||||
let tree = KdTree<float, int> (2, KdTree.Math.DoubleMath ())
|
||||
|
||||
do points |> Array.iter (fun a -> tree.Add ([| fst a.Pos; snd a.Pos |], a.Data) |> ignore)
|
||||
if points.Length > 0 then
|
||||
tree.Balance()
|
||||
do tree.Balance ()
|
||||
else
|
||||
Log.Warning $"Empty kd-tree"
|
||||
do Log.Warning $"Empty kd-tree"
|
||||
|
||||
tree
|
||||
|
||||
type private Ean = Map<NodeIdx, ElemIdx array>
|
||||
|
||||
let private makeElemsSurroundingNodeMap (elem: Elem array) : ElemsAroundNode =
|
||||
let addElIdx k v (nodes: Ean) =
|
||||
Map.tryFind k nodes
|
||||
|> Option.defaultWith (fun () -> [])
|
||||
|> fun nds -> Map.add k (v :: nds) nodes
|
||||
elem
|
||||
|> Array.fold
|
||||
(fun (n, acc) (a, b, c) ->
|
||||
let acc' =
|
||||
acc
|
||||
|> addElIdx a n
|
||||
|> addElIdx b n
|
||||
|> addElIdx c n
|
||||
n + 1, acc')
|
||||
(0, Map.empty)
|
||||
let addElIdx k v (nodes: Ean) : Ean =
|
||||
let nds =
|
||||
Map.tryFind k nodes
|
||||
|> Option.defaultValue [||]
|
||||
nodes |> Map.add k (Array.append [|v|] nds)
|
||||
let folder (n, acc) (a, b, c) =
|
||||
let acc' = acc |> addElIdx a n |> addElIdx b n |> addElIdx c n
|
||||
n + 1, acc'
|
||||
|
||||
((0, Map.empty), elem)
|
||||
||> Array.fold folder
|
||||
|> snd
|
||||
|> Map.mapValues toArray
|
||||
|
||||
let private makeElemsSurroundingNodeMap' (elem: Elem array) : ElemsAroundNode =
|
||||
let addElemIdx k v nodes =
|
||||
@@ -127,12 +100,9 @@ let private makeElemsSurroundingNodeMap' (elem: Elem array) : ElemsAroundNode =
|
||||
elem
|
||||
|> Array.fold
|
||||
(fun (n, acc) (a, b, c) ->
|
||||
let acc' =
|
||||
acc
|
||||
|> addElemIdx a n
|
||||
|> addElemIdx b n
|
||||
|> addElemIdx c n
|
||||
n + 1, acc')
|
||||
let acc' = acc |> addElemIdx a n |> addElemIdx b n |> addElemIdx c n
|
||||
n + 1, acc'
|
||||
)
|
||||
(0, Map.empty)
|
||||
|> snd
|
||||
|> Map.mapValues toArray
|
||||
@@ -143,28 +113,45 @@ let private makeNodesSurroudingNodeMap (n2e: ElemsAroundNode) (elem: Elem array)
|
||||
n
|
||||
|> Array.collect (fun x ->
|
||||
let n1, n2, n3 = elem[x]
|
||||
[| n1; n2; n3 |])
|
||||
|> Array.distinct)
|
||||
[| n1; n2; n3 |]
|
||||
)
|
||||
|> Array.distinct
|
||||
)
|
||||
|
||||
let getSurrounding (idx: Map<int, int []>) (a, b, c) =
|
||||
[| idx[a]; idx[b]; idx[c] |]
|
||||
|> Array.concat
|
||||
|> Array.distinct
|
||||
let private makeElemsSurroundingElemMap (ean: ElemsAroundNode) (elem: Elem array) : ElemsAroundElem =
|
||||
elem
|
||||
|> Array.mapi (fun elemIdx (n1, n2, n3) ->
|
||||
// For each element, find all elements that share any of its nodes
|
||||
let surroundingElems =
|
||||
[| ean[n1]; ean[n2]; ean[n3] |]
|
||||
|> Array.concat
|
||||
|> Array.distinct
|
||||
|> Array.filter (fun x -> x <> elemIdx) // Remove self
|
||||
elemIdx, surroundingElems
|
||||
)
|
||||
|> Map.ofArray
|
||||
|
||||
let getSurrounding (idx: Map<int, int[]>) (a, b, c) =
|
||||
[| idx[a]; idx[b]; idx[c] |] |> Array.concat |> Array.distinct
|
||||
|
||||
let makeNeighborIndex (grid: IGrid) =
|
||||
let elem = grid.getCells ()
|
||||
let ean = makeElemsSurroundingNodeMap elem
|
||||
|
||||
{
|
||||
ElemsAroundNode = ean
|
||||
NodesAroundNode = makeNodesSurroudingNodeMap ean elem
|
||||
ElemsAroundElem = makeElemsSurroundingElemMap ean elem
|
||||
}
|
||||
|
||||
let getElemsSurroundingNode (idx: NeighborIndex) n = idx.ElemsAroundNode[n]
|
||||
|
||||
let getNodesSurroundingNode (idx: NeighborIndex) n = idx.NodesAroundNode[n]
|
||||
|
||||
let getNodesSurroundingElem (idx: NeighborIndex) (grid: Grid) e =
|
||||
getSurrounding idx.NodesAroundNode grid.Elem[e]
|
||||
let getNodesSurroundingElem (idx: NeighborIndex) e = idx.ElemsAroundElem[e]
|
||||
|
||||
// let getNodesSurroundingElem (idx: NeighborIndex) (grid: Grid) e =
|
||||
// getSurrounding idx.NodesAroundNode grid.Elem[e]
|
||||
|
||||
let getElemsSurroundingElem (idx: NeighborIndex) (grid: Grid) e =
|
||||
getSurrounding idx.ElemsAroundNode grid.Elem[e]
|
||||
@@ -201,45 +188,68 @@ let bboxToLngLat (coordsys: CoordinateSystem) b =
|
||||
let projectBBox proj b =
|
||||
let x0, y0 = proj (b.minX, b.minY)
|
||||
let x1, y1 = proj (b.maxX, b.maxY)
|
||||
{ minX = x0; maxX = x1; minY = y0; maxY = y1; center = proj b.center }
|
||||
{
|
||||
minX = x0
|
||||
maxX = x1
|
||||
minY = y0
|
||||
maxY = y1
|
||||
center = proj b.center
|
||||
}
|
||||
|
||||
let projectGrid proj (grid: Grid) : Grid =
|
||||
{ grid with
|
||||
let projectGrid proj (grid: Grid) : Grid = {
|
||||
grid with
|
||||
Nodes = grid.Nodes |> Array.Parallel.map proj
|
||||
BBox = projectBBox proj grid.BBox
|
||||
}
|
||||
}
|
||||
|
||||
let rescaleGrid (factor: float) (grid: Grid) : Grid =
|
||||
let nodes' = grid.Nodes |> Array.Parallel.map (fun (x, y) -> factor * x, factor * y)
|
||||
let bbox' = calcBBox nodes'
|
||||
{ grid with Nodes = nodes'; BBox = bbox' }
|
||||
|
||||
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 s = System.Diagnostics.Stopwatch.StartNew ()
|
||||
let g = grid |> projectGrid toWebMercator.project
|
||||
s.Stop()
|
||||
s.Stop ()
|
||||
Log.Debug $"Reprojected grid: {s.ElapsedMilliseconds} ms"
|
||||
g
|
||||
|
||||
let toLonLat (coordsys: CoordinateSystem) (grid: Grid) =
|
||||
let toLonLat = makeTransform coordsys CoordSys.WGS84
|
||||
let s = System.Diagnostics.Stopwatch.StartNew ()
|
||||
let g = grid |> projectGrid toLonLat.project
|
||||
s.Stop ()
|
||||
Log.Debug $"Reprojected grid: {s.ElapsedMilliseconds} ms"
|
||||
g
|
||||
|
||||
let private chomp (l: string) = l.Split ' ' |> Array.filter ((<>) "")
|
||||
|
||||
// TODO: pattern match and compare sizes for more flex
|
||||
let private readGrdHeader (h: string []) =
|
||||
let private readGrdHeader (h: string[]) =
|
||||
let parse x = (chomp x)[3] |> int
|
||||
try
|
||||
let nodes = parse h[0]
|
||||
let nele = parse h[1]
|
||||
Some(nodes, nele)
|
||||
with
|
||||
| _ -> None
|
||||
Some (nodes, nele)
|
||||
with _ ->
|
||||
None
|
||||
|
||||
let private readObcHeader (h: string) =
|
||||
try
|
||||
(chomp h)[4] |> int |> Some
|
||||
with
|
||||
| _ -> None
|
||||
with _ ->
|
||||
None
|
||||
|
||||
let private reader (parser: string [] -> 'a) (f: string array) =
|
||||
let private reader (parser: string[] -> 'a) (f: string array) =
|
||||
try
|
||||
f |> Array.map (chomp >> parser) |> Some
|
||||
with
|
||||
| e ->
|
||||
with e ->
|
||||
Log.Error e.Message
|
||||
None
|
||||
|
||||
@@ -276,15 +286,14 @@ let readGrdFile (filename: string) =
|
||||
let els, nds = Array.splitAt nele rest
|
||||
let elem = readElem els
|
||||
let nodes = readNodes nds
|
||||
let toGrid e n =
|
||||
{ Grid.empty with Elem = e; Nodes = n; BBox = calcBBox n }
|
||||
toGrid <!> elem <*> nodes)
|
||||
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) =
|
||||
@@ -298,11 +307,8 @@ module Boundary =
|
||||
match Map.tryFind edge a with
|
||||
| Some v -> Map.add edge (n :: v) a
|
||||
| None -> Map.add edge [ n ] a
|
||||
let appendEdges a (n, x: Edge []) =
|
||||
a
|
||||
|> appendEdge (n, x[0])
|
||||
|> appendEdge (n, x[1])
|
||||
|> appendEdge (n, x[2])
|
||||
let appendEdges a (n, x: Edge[]) =
|
||||
a |> appendEdge (n, x[0]) |> appendEdge (n, x[1]) |> appendEdge (n, x[2])
|
||||
grid.Elem
|
||||
|> Array.mapi normElIdx
|
||||
|> Array.fold appendEdges Map.empty
|
||||
@@ -320,8 +326,7 @@ module Boundary =
|
||||
|> Map.mapValues (fun x -> List.head x, List.last x)
|
||||
|
||||
let makeBoundaryByElementMap (edgeMap: Map<Edge, ElemIdx>) =
|
||||
edgeMap
|
||||
|> Map.fold (fun a k v -> Map.add v k a) Map.empty
|
||||
edgeMap |> Map.fold (fun a k v -> Map.add v k a) Map.empty
|
||||
|
||||
let getBoundaryNodesArray (edgeMap: Map<Edge, ElemIdx>) =
|
||||
edgeMap
|
||||
@@ -341,8 +346,7 @@ module Util =
|
||||
(x0 + x1 + x2) / 3f, (y0 + y1 + y2) / 3f
|
||||
|
||||
static member calcArea((x0, y0), (x1, y1), (x2, y2)) =
|
||||
x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)
|
||||
|> (*) 0.5
|
||||
x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1) |> (*) 0.5
|
||||
|
||||
// static member calcArea((x0, y0), (x1, y1), (x2, y2)) =
|
||||
// x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)
|
||||
@@ -360,30 +364,47 @@ module Util =
|
||||
let Sy = det Tx T2 E |> (*) 0.5
|
||||
let a = det Tx Ty E
|
||||
let b = det Tx Ty T2
|
||||
if abs a < 1.0e-12 then failwith "co-linear vertices"
|
||||
if abs a < 1.0e-12 then
|
||||
failwith "co-linear vertices"
|
||||
let S2 = (Sx, Sy) |> square
|
||||
let r = (b / a + S2 / (a * a)) |> sqrt
|
||||
Sx / a, Sy / a, r
|
||||
|
||||
static member propToNodal (nIdx: NeighborIndex) (s: float []) =
|
||||
[| 0 .. nIdx.NodesAroundNode.Count - 1 |]
|
||||
static member propToNodal (nIdx: NeighborIndex) (s: float[]) =
|
||||
[| 0 .. nIdx.NodesAroundNode.Count - 1 |] // total number of nodes
|
||||
|> Array.Parallel.map (fun i ->
|
||||
let ns = nIdx.ElemsAroundNode[i]
|
||||
ns
|
||||
|> Array.fold (fun a n -> s[n] + a) 0.
|
||||
|> (*) (1. / float ns.Length))
|
||||
ns |> Array.fold (fun a n -> s[n] + a) 0. |> (*) (1. / float ns.Length)
|
||||
)
|
||||
|
||||
static member speedToNodal (nIdx: NeighborIndex) (s: (float * float) []) =
|
||||
[| 0 .. nIdx.NodesAroundNode.Count - 1 |]
|
||||
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)
|
||||
sqrt (u * u + v * v) + a
|
||||
)
|
||||
0.
|
||||
|> (*) (1. / float ns.Length))
|
||||
|> (*) (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) =
|
||||
@@ -402,8 +423,10 @@ module Util =
|
||||
let centroid = Element.calcCentroid (p0, p1, p2)
|
||||
let a1 = Element.calcArea (p0', p1', p2')
|
||||
let a2 = Element.calcArea (p1', centroid, p2')
|
||||
a1 + a2)
|
||||
|> Array.sum)
|
||||
a1 + a2
|
||||
)
|
||||
|> Array.sum
|
||||
)
|
||||
|
||||
static member calcNodeArea (idx: NeighborIndex) (grid: IGrid) =
|
||||
let nodes = grid.getVertices ()
|
||||
@@ -411,7 +434,8 @@ module Util =
|
||||
|> Array.Parallel.map (fun n ->
|
||||
getElemsSurroundingNode idx n
|
||||
|> Array.map (grid.getCellVertices >> Element.calcArea)
|
||||
|> Array.sum)
|
||||
|> Array.sum
|
||||
)
|
||||
|
||||
let calcCentroids (grid: IGrid) =
|
||||
let n = grid.getVertices ()
|
||||
@@ -420,42 +444,29 @@ module Util =
|
||||
let p0 = n[a]
|
||||
let p1 = n[b]
|
||||
let p2 = n[c]
|
||||
Element.calcCentroid (p0, p1, p2))
|
||||
Element.calcCentroid (p0, p1, p2)
|
||||
)
|
||||
|
||||
let inline isInsideTriangle (x, y, z) p =
|
||||
let sign (p1x, p1y) (p2x, p2y) (p3x, p3y) =
|
||||
(p1x - p3x) * (p2y - p3y)
|
||||
- (p2x - p3x) * (p1y - p3y)
|
||||
(p1x - p3x) * (p2y - p3y) - (p2x - p3x) * (p1y - p3y)
|
||||
|
||||
let d1 = sign p x y
|
||||
let d2 = sign p y z
|
||||
let d3 = sign p z x
|
||||
|
||||
let neg = (d1 <= 0.) || (d2 <= 0.) || (d3 <= 0.)
|
||||
let pos = (d1 >= 0.) || (d2 >= 0.) || (d3 >= 0.)
|
||||
let neg = (d1 < 0.) || (d2 < 0.) || (d3 < 0.)
|
||||
let pos = (d1 > 0.) || (d2 > 0.) || (d3 > 0.)
|
||||
|
||||
neg && pos |> not
|
||||
|
||||
let inline isInsideTriangle_dbl (x, y, z) p =
|
||||
let sign (p1x, p1y) (p2x, p2y) (p3x, p3y) =
|
||||
(p1x - p3x) * (p2y - p3y)
|
||||
- (p2x - p3x) * (p1y - p3y)
|
||||
|
||||
let d1 = sign p x y
|
||||
let d2 = sign p y z
|
||||
let d3 = sign p z x
|
||||
|
||||
let neg = (d1 <= 0.0) || (d2 <= 0.0) || (d3 <= 0.0)
|
||||
let pos = (d1 >= 0.0) || (d2 >= 0.0) || (d3 >= 0.0)
|
||||
|
||||
neg && pos |> not
|
||||
(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 = x; Y = y }; Data = i })
|
||||
{ Pos = x, y; Data = i }
|
||||
)
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createTree
|
||||
|
||||
@@ -463,12 +474,10 @@ module Util =
|
||||
let buildNearestElementTree (grid: IGrid) =
|
||||
grid.getCells ()
|
||||
|> Array.mapi (fun i _ ->
|
||||
let pos =
|
||||
i
|
||||
|> grid.getCellVertices
|
||||
|> Element.calcCentroid
|
||||
|> fun (x, y) -> { X = x; Y = y }
|
||||
{ Pos = pos; Data = i })
|
||||
let pos = i |> grid.getCellVertices |> Element.calcCentroid
|
||||
// |> fun (x, y) -> { X = x; Y = y }
|
||||
{ Pos = pos; Data = i }
|
||||
)
|
||||
// |> create2DTree treeLeafSize
|
||||
|> createTree
|
||||
|
||||
@@ -484,25 +493,38 @@ module Util =
|
||||
// else None)
|
||||
|
||||
let tryFindElement (grid: IGrid) (tree: KdTree<float, int>) ((p0, p1): float * float) =
|
||||
tree.GetNearestNeighbours([| p0; p1 |], 1)
|
||||
tree.GetNearestNeighbours ([| p0; p1 |], 1)
|
||||
|> Array.tryHead
|
||||
|> Option.bind (fun leaf ->
|
||||
let vx = grid.getCellVertices leaf.Value
|
||||
if isInsideTriangle vx (p0, p1) then
|
||||
Some leaf.Value
|
||||
else
|
||||
None)
|
||||
None
|
||||
)
|
||||
|
||||
// type private IdxTree = Tree<Leaf<single, ElemIdx> array, Node<single>>
|
||||
// type private NodeIdxTree = Tree<Leaf<single, NodeIdx> array, Node<single>>
|
||||
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 centroids: Vertex[] option = None
|
||||
let mutable gridHash: byte[] = [||]
|
||||
|
||||
let getNeighborIdx () =
|
||||
match neighborIndex with
|
||||
@@ -512,87 +534,117 @@ type ExtendedGrid(grid: IGrid) =
|
||||
neighborIndex.Value
|
||||
|
||||
interface IGrid with
|
||||
member x.getVertex n = grid.getVertex n
|
||||
member x.getCell n = grid.getCell n
|
||||
member x.getCellVertices n = grid.getCellVertices n
|
||||
member x.getVertices() = grid.getVertices ()
|
||||
member x.getCells() = grid.getCells ()
|
||||
member x.getBoundingBox() = grid.getBoundingBox ()
|
||||
member x.Projection = grid.Projection
|
||||
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 x.NeighborIndex = neighborIndex
|
||||
member x.NodeTree = nodeTree
|
||||
member x.ElementTree = elementTree
|
||||
member this.NeighborIndex = neighborIndex
|
||||
member this.NodeTree = nodeTree
|
||||
member this.ElementTree = elementTree
|
||||
|
||||
member x.Grid = grid
|
||||
member this.Grid = grid
|
||||
|
||||
member x.initNeighborIndex(?cache: string) =
|
||||
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 x.initNodeTree() =
|
||||
member this.initNodeTree() =
|
||||
match nodeTree with
|
||||
| Some _ -> ()
|
||||
| None -> nodeTree <- Util.buildNearestNodeTree grid |> Some
|
||||
|
||||
member x.initElementTree() =
|
||||
member this.initElementTree() =
|
||||
match elementTree with
|
||||
| Some _ -> ()
|
||||
| None -> elementTree <- Util.buildNearestElementTree grid |> Some
|
||||
|
||||
member x.nearestNode(p0: float, p1: float) =
|
||||
member this.nearestNode(p0: float, p1: float) =
|
||||
let nearest (tree: KdTree<_, _>) =
|
||||
tree.GetNearestNeighbours([| p0; p1 |], 1)
|
||||
tree.GetNearestNeighbours ([| p0; p1 |], 1)
|
||||
|> Array.tryHead
|
||||
|> Option.map (fun l -> l.Value)
|
||||
match nodeTree with
|
||||
| Some tree -> nearest tree
|
||||
| None ->
|
||||
x.initNodeTree ()
|
||||
this.initNodeTree ()
|
||||
nearest nodeTree.Value
|
||||
|
||||
member x.tryGetNode(p: float * float) =
|
||||
x.nearestNode p
|
||||
member this.tryGetNode(p: float * float) =
|
||||
this.nearestNode p
|
||||
|> Option.bind (fun n ->
|
||||
x.getElemsSurroundingNode n
|
||||
|> Array.fold (fun (a: int option) e ->
|
||||
if a.IsNone then
|
||||
let vx = x.Grid.getCellVertices e
|
||||
if Util.isInsideTriangle vx p then Some n else None
|
||||
else a) None
|
||||
)
|
||||
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 x.tryFindElementTwice (grid: IGrid) (tree: IdxTree) ((p0, p1): float * float as p) =
|
||||
match Util.tryFindElement grid tree p with
|
||||
| Some elemIdx -> Some elemIdx
|
||||
| None ->
|
||||
tree.GetNearestNeighbours([| p0; p1 |], 1)
|
||||
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 ->
|
||||
x.getElemsSurroundingElem leaf.Value
|
||||
this.getElemsSurroundingElem leaf.Value
|
||||
|> Array.tryFind (fun eIdx ->
|
||||
let vx = x.Grid.getCellVertices eIdx
|
||||
Util.isInsideTriangle vx p))
|
||||
let vx = this.Grid.getCellVertices eIdx
|
||||
Util.isInsideTriangle vx p
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
member x.tryGetElement p =
|
||||
match elementTree with
|
||||
| Some tree -> x.tryFindElementTwice grid tree p
|
||||
| None ->
|
||||
x.initElementTree ()
|
||||
Log.Debug $"You shouldn't be here!"
|
||||
// x.initNodeTree ()
|
||||
x.tryFindElementTwice grid elementTree.Value 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 x.tryGetElementSloppy(p0, p1 as p) =
|
||||
member this.tryGetElementSloppy(p0, p1 as p) =
|
||||
match elementTree with
|
||||
| Some tree -> Util.tryFindElement grid tree p
|
||||
| None ->
|
||||
x.initElementTree ()
|
||||
// x.initNodeTree ()
|
||||
this.initElementTree ()
|
||||
// this.initNodeTree ()
|
||||
Util.tryFindElement grid elementTree.Value p
|
||||
|
||||
member x.getCentroids() =
|
||||
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 ->
|
||||
@@ -600,58 +652,55 @@ type ExtendedGrid(grid: IGrid) =
|
||||
centroids <- Some cx
|
||||
cx
|
||||
|
||||
member x.calcCircumCircle e =
|
||||
member this.calcCircumCircle e =
|
||||
let triangle = grid.getCellVertices e
|
||||
Util.Element.calcCircumscribedCircle triangle
|
||||
|
||||
member x.getElemsSurroundingNode n =
|
||||
getNeighborIdx ()
|
||||
|> fun idx -> idx.ElemsAroundNode[n]
|
||||
member this.getElemsSurroundingNode n =
|
||||
getNeighborIdx () |> fun idx -> idx.ElemsAroundNode[n]
|
||||
|
||||
member x.getNodesSurroundingNode n =
|
||||
getNeighborIdx ()
|
||||
|> fun idx -> idx.NodesAroundNode[n]
|
||||
member this.getNodesSurroundingNode n =
|
||||
getNeighborIdx () |> fun idx -> idx.NodesAroundNode[n]
|
||||
|
||||
member x.getNodesSurroundingElem e =
|
||||
member this.getNodesSurroundingElem e =
|
||||
let idx = getNeighborIdx ()
|
||||
let elem = grid.getCell e
|
||||
getSurrounding idx.NodesAroundNode elem
|
||||
|
||||
member x.getElemsSurroundingElem e =
|
||||
member this.getElemsSurroundingElem e =
|
||||
let idx = getNeighborIdx ()
|
||||
let elem = grid.getCell e
|
||||
getSurrounding idx.ElemsAroundNode elem
|
||||
|
||||
member x.saveNeighborIndex(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
member this.saveNeighborIndex(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let nix = getNeighborIdx ()
|
||||
let pickle = binarySerializer.Pickle nix
|
||||
IO.File.WriteAllBytes(fname, pickle)
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member x.loadNeighborIndex(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
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
|
||||
neighborIndex <- binarySerializer.UnPickle<NeighborIndex> pickle |> Some
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
member x.saveNodeTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
member this.saveNodeTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let tree =
|
||||
nodeTree
|
||||
|> Option.defaultWith (fun () ->
|
||||
x.initNodeTree ()
|
||||
nodeTree.Value)
|
||||
this.initNodeTree ()
|
||||
nodeTree.Value
|
||||
)
|
||||
|
||||
let pickle = binarySerializer.Pickle tree
|
||||
IO.File.WriteAllBytes(fname, pickle)
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member x.loadNodeTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
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
|
||||
@@ -659,22 +708,23 @@ type ExtendedGrid(grid: IGrid) =
|
||||
else
|
||||
false
|
||||
|
||||
member x.saveElementTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
member this.saveElementTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer ()
|
||||
let tree =
|
||||
elementTree
|
||||
|> Option.defaultWith (fun () ->
|
||||
x.initElementTree ()
|
||||
elementTree.Value)
|
||||
this.initElementTree ()
|
||||
elementTree.Value
|
||||
)
|
||||
|
||||
let pickle = binarySerializer.Pickle tree
|
||||
IO.File.WriteAllBytes(fname, pickle)
|
||||
IO.File.WriteAllBytes (fname, pickle)
|
||||
|
||||
member x.loadElementTree(fname: string) =
|
||||
let binarySerializer = FsPickler.CreateBinarySerializer()
|
||||
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
|
||||
false
|
||||
@@ -8,8 +8,8 @@ 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
|
||||
@@ -21,9 +21,10 @@ let private calcInterpolationWeightedIdx (rn, fn) =
|
||||
let nearestIdx = Array.map (fun fzi -> findNearestZ fzi rn) fn
|
||||
nearestIdx
|
||||
|> Array.mapi (fun i j ->
|
||||
let last = Array.last rn
|
||||
if fn[i] <= rn[0] then
|
||||
(0, 0), (1.0, 0.0)
|
||||
elif fn[i] >= rn[^0] then
|
||||
elif fn[i] >= last then
|
||||
(rn.Length - 1, 0), (1.0, 0.0)
|
||||
elif abs (fn[i] - rn[j]) < 9.999999975e-07 then
|
||||
(j, 0), (1.0, 0.0)
|
||||
@@ -40,42 +41,36 @@ 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
|
||||
|
||||
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
|
||||
|
||||
type BiWght = float * float * float * float
|
||||
type BiProp = float * float * float * float
|
||||
@@ -92,47 +87,43 @@ let genBilinearInterpolationWgts
|
||||
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
|
||||
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
|
||||
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)
|
||||
Some (w00, w10, w11, w01)
|
||||
else
|
||||
None
|
||||
|
||||
let makeBiWeights
|
||||
(pos: (float * float) [])
|
||||
(boxes: ((float * float) * (float * float) * (float * float) * (float * float)) [])
|
||||
(mask: (bool * bool * bool * bool) [])
|
||||
(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 []) =
|
||||
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)
|
||||
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 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 private fillOutOfBounds (grid: Grid) (interpVal: float option[]) =
|
||||
let node = interpVal.Length = grid.Nodes.Length
|
||||
let nbridx = makeNeighborIndex (grid :> IGrid)
|
||||
let mutable allval = valtest interpVal
|
||||
@@ -141,24 +132,20 @@ let private fillOutOfBounds (grid: Grid) (interpVal: float option []) =
|
||||
if Option.isNone interpVal[n] then
|
||||
let nb =
|
||||
if node then
|
||||
nbridx.NodesAroundNode[n]
|
||||
|> Array.filter (fun k -> Option.isSome interpVal[k])
|
||||
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
|
||||
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 [,])
|
||||
(pos: (float * float)[])
|
||||
(prop: float[,])
|
||||
(fvgrid: Grid)
|
||||
(oob: bool)
|
||||
=
|
||||
@@ -189,7 +176,7 @@ let interpolateProp
|
||||
else
|
||||
iprop |> Array.map (fun v -> v.Value)
|
||||
|
||||
let interpCoefs (coords, _ as grid: BiPos * Mask) (pos: (float * float) []) =
|
||||
let interpCoefs (coords, _ as grid: BiPos * Mask) (pos: (float * float)[]) =
|
||||
let cm = getNearestCellCorner grid pos
|
||||
let boxes, mask =
|
||||
cm
|
||||
@@ -198,12 +185,10 @@ let interpCoefs (coords, _ as grid: BiPos * Mask) (pos: (float * float) []) =
|
||||
|> Array.unzip
|
||||
let wgths = makeBiWeights pos boxes mask
|
||||
let corneridx =
|
||||
cm
|
||||
|> Array.map (fun c -> Array.unzip c)
|
||||
|> Array.map (fun (i, _) -> i)
|
||||
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 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]))
|
||||
|
||||
@@ -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,8 +41,7 @@ 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)
|
||||
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageId>Oceanbox.FvcomKit</PackageId>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Company>Oceanbox AS</Company>
|
||||
<Authors/>
|
||||
<Company/>
|
||||
<Version>5.0.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="Polygon.fs"/>
|
||||
@@ -24,20 +26,21 @@
|
||||
<Compile Include="Smoothing.fs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Update="FSharp.Core" Version="6.0.5"/>
|
||||
<PackageReference Include="FSharp.Data" Version="6.0.1-beta001"/>
|
||||
<PackageReference Include="FSharpPlus" Version="1.3.0-CI02744"/>
|
||||
<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="sdslite" Version="2.5.0"/>
|
||||
<PackageReference Include="Serilog" Version="2.12.0"/>
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.1-dev-00896"/>
|
||||
<PackageReference Include="Serilog.Sinks.Seq" Version="5.2.1"/>
|
||||
<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>
|
||||
<ProjectReference Include="..\submodules\ProjNet.FSharp\src\ProjNet.FSharp.fsproj"/>
|
||||
<ProjectReference Include="..\submodules\FsKdTree\lib\FsKDTree.fsproj"/>
|
||||
<PackageUpdate Include="ProjNet.FSharp" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' "/>
|
||||
<PackageUpdate Include="Oceanbox.SDSLite" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' "/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
type Point = float * float
|
||||
|
||||
type Polygon = Point []
|
||||
type Polygon = Point[]
|
||||
|
||||
let private maxdist (pol: Polygon) (pnt: Point) =
|
||||
pol
|
||||
@@ -28,10 +28,7 @@ let private onsegment (p: Polygon) =
|
||||
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
|
||||
if x[2] >= minx && x[2] <= maxx && y[2] >= miny && y[2] <= maxy then
|
||||
true
|
||||
else
|
||||
false
|
||||
@@ -56,8 +53,7 @@ let private intersect (p1: Polygon) (p2: Polygon) =
|
||||
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 (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
|
||||
|
||||
186
src/ROMS.fs
186
src/ROMS.fs
@@ -11,36 +11,33 @@ open Adjoin
|
||||
open Interpol
|
||||
|
||||
type GridData<'a> = { rho: 'a; u: 'a; v: 'a }
|
||||
type GridMask = GridData<bool [,]>
|
||||
type GridMask = GridData<bool[,]>
|
||||
type GridPos = GridData<BiPos>
|
||||
type GridVars = GridData<float [,]>
|
||||
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[][]
|
||||
}
|
||||
|
||||
type FvcomGrid = Fvcom.FvcomGrid
|
||||
|
||||
@@ -49,58 +46,45 @@ let private layerZ csR (vars: GridVars) =
|
||||
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..."
|
||||
@@ -119,32 +103,29 @@ 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
|
||||
@@ -152,31 +133,28 @@ let readGrid (nc: DataSet) =
|
||||
|
||||
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
|
||||
@@ -201,13 +179,13 @@ let genRomsToFvcomAdjoints (proj: IProj) (fvcom: Grid) (roms: RomsGrid) =
|
||||
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 (proj: IProj) (fvcom: Grid) (roms: RomsGrid) (props: RomsProps) =
|
||||
@@ -216,8 +194,7 @@ let adjoinRomsToFvcom (proj: IProj) (fvcom: Grid) (roms: RomsGrid) (props: RomsP
|
||||
|
||||
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: FvcomGrid) (u, v) =
|
||||
let h = fvcom.Bathymetry
|
||||
@@ -231,23 +208,18 @@ let calcUVBar (fvcom: FvcomGrid) (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
|
||||
@@ -256,9 +228,7 @@ let calcUVBar (fvcom: FvcomGrid) (u, 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)
|
||||
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
|
||||
|
||||
@@ -7,61 +7,61 @@ 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 (idx: NeighborIndex) (prop: single []) =
|
||||
idx.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 (idx: NeighborIndex) (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, *] <- idx.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 (idx: NeighborIndex) (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, *] <- idx.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 (idx: NeighborIndex) (grid: Grid) (prop: single []) =
|
||||
let smoothElements (idx: NeighborIndex) (grid: Grid) (prop: single[]) =
|
||||
grid.Elem
|
||||
|> Array.Parallel.mapi (fun n _ ->
|
||||
let elems = getElemsSurroundingElem idx grid n
|
||||
smooth prop elems)
|
||||
|
||||
let smoothElements2D (idx: NeighborIndex) (grid: Grid) (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 idx grid prop[k, *]
|
||||
prop
|
||||
|
||||
let smoothElements3D (idx: NeighborIndex) (grid: Grid) (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 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
|
||||
@@ -73,34 +73,34 @@ let private rectifyOob (getSurrounding: int -> int []) (oob: int []) (prop: sing
|
||||
rectify oob
|
||||
prop
|
||||
|
||||
let rectifyOutOfBoundsNodes (idx: NeighborIndex) (oob: int []) (prop: single []) =
|
||||
let rectifyOutOfBoundsNodes (idx: NeighborIndex) (oob: int[]) (prop: single[]) =
|
||||
let f = getNodesSurroundingNode idx
|
||||
rectifyOob f oob prop
|
||||
|
||||
let rectifyOutOfBoundsNodes2D (idx: NeighborIndex) (oob: int []) (prop: single [,]) =
|
||||
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 (idx: NeighborIndex) (oob: int []) (prop: single [,,]) =
|
||||
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 (idx: NeighborIndex) (grid: Grid) (oob: int []) (prop: single []) =
|
||||
let rectifyOutOfBoundsElements (idx: NeighborIndex) (grid: Grid) (oob: int[]) (prop: single[]) =
|
||||
let f = getElemsSurroundingElem idx grid
|
||||
rectifyOob f oob prop
|
||||
|
||||
let rectifyOutOfBoundsElements2D (idx: NeighborIndex) (grid: Grid) (oob: int []) (prop: single [,]) =
|
||||
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 (idx: NeighborIndex) (grid: Grid) (oob: int []) (prop: single [,,]) =
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
25
src/Types.fs
25
src/Types.fs
@@ -2,7 +2,26 @@ module Oceanbox.FvcomKit.Types
|
||||
|
||||
open System
|
||||
|
||||
let unzip2D (array: _ [,]) =
|
||||
type Vertex = float * float
|
||||
|
||||
[<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
|
||||
@@ -14,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
|
||||
@@ -23,7 +42,7 @@ 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
|
||||
|
||||
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="
|
||||
}
|
||||
]
|
||||
Submodule submodules/FsKdTree deleted from b6e14c0a81
Submodule submodules/ProjNet.FSharp deleted from 5b7509ca1b
@@ -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,16 +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" />
|
||||
</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