Skip to content

Commit

Permalink
CI, formatting, linting (#32)
Browse files Browse the repository at this point in the history
- Added [dev] optional to package (pip install ".[dev]")
- Added tools formatting & linting to the [dev] optional
- Added script that runs these tools and applies fixes whenever able
- Added CI that checks code using these tools
- Adjusted code to pass checks (no functional changes)
  • Loading branch information
surgura authored and VeckoTheGecko committed Sep 25, 2024
1 parent b00793e commit a4444e6
Show file tree
Hide file tree
Showing 10 changed files with 482 additions and 136 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/codetools.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: ci

on: [push, pull_request]

env:
PACKAGE: virtual_ship

jobs:
codetools:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/[email protected]
with:
python-version: ${{ matrix.python-version }}
- name: install
run: pip install ".[dev]"
- name: flake8
run: flake8 ./$PACKAGE
- name: pydocstyle
run: pydocstyle ./$PACKAGE
- name: sort-all
run: |
find ./$PACKAGE -type f -name '__init__.py' -print0 | xargs -0 sort-all
[[ -z $(git status -s) ]]
git checkout -- .
- name: black
run: black --diff --check ./$PACKAGE
- name: isort
run: isort --check-only --diff ./$PACKAGE
38 changes: 38 additions & 0 deletions codetools.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/sh

# Runs all codetools and attempts to apply fixes wherever possible.
# Not suitable for the CI as that should not make any changes.

set -e

# Set working directory to the directory of this script.
cd "$(dirname "$0")"

PACKAGE=virtual_ship

echo "--------------"
echo "flake8"
echo "--------------"
flake8 ./$PACKAGE
# darglint is ran as a plugin for flake8.

echo "--------------"
echo "pydocstyle"
echo "--------------"
pydocstyle ./$PACKAGE

echo "--------------"
echo "sort-all"
echo "--------------"
find ./$PACKAGE -type f -name '__init__.py' -print0 | xargs -0 sort-all

echo "--------------"
echo "black"
echo "--------------"
black ./$PACKAGE

echo "--------------"
echo "isort"
echo "--------------"
isort ./$PACKAGE

17 changes: 15 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies = [
"pyproj >= 3, < 4",
"parcels >= 3, < 4",
"scipy >= 1, < 2",
"xarray >= 2023, < 2024"
"xarray >= 2023, < 2024",
]

[project.urls]
Expand All @@ -44,8 +44,21 @@ packages = ["virtual_ship"]
write_to = "virtual_ship/_version_setup.py"
local_scheme = "no-local-version"

[project.optional-dependencies]
dev = [
"black == 24.4.0",
"darglint == 1.8.1",
"flake8 == 7.0.0",
"Flake8-pyproject == 1.2.3",
"isort == 5.13.2",
"pydocstyle == 6.3.0",
"sort-all == 1.2.0",
]

[tool.isort]
profile = "black"
skip_gitignore = true

# Other tools will be added soon.
[tool.flake8]
extend-ignore = "E501" # Don't check line length.
docstring_style = "sphinx" # Use sphinx docstring style for darglint plugin.
1 change: 1 addition & 0 deletions virtual_ship/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Code for the Virtual Ship Classroom, where Marine Scientists can combine Copernicus Marine Data with an OceanParcels ship to go on a virtual expedition."""
119 changes: 93 additions & 26 deletions virtual_ship/argo_deployments.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import os
import math
import numpy as np
"""argo_deployments function."""

import datetime
import math
import os
from datetime import timedelta
from parcels import FieldSet, JITParticle, Variable, ParticleSet, AdvectionRK4, StatusCode

import numpy as np
from parcels import (
AdvectionRK4,
FieldSet,
JITParticle,
ParticleSet,
StatusCode,
Variable,
)


def argo_deployments(config, argo_time):
'''Deploys argo floats, returns results folder'''
"""
Deploy argo floats.
:param config: The cruise configuration.
:param argo_time: TODO
"""
# particle_* such as particle_ddepth are local variables defined by parcels.
# See https://docs.oceanparcels.org/en/latest/examples/tutorial_kernelloop.html#Background

if len(config.argo_deploylocations) > 0:

Expand All @@ -17,7 +35,9 @@ def ArgoVerticalMovement(particle, fieldset, time):

if particle.cycle_phase == 0:
# Phase 0: Sinking with vertical_speed until depth is driftdepth
particle_ddepth += fieldset.vertical_speed * particle.dt
particle_ddepth += ( # noqa See comment above about particle_* variables.
fieldset.vertical_speed * particle.dt
)
if particle.depth + particle_ddepth <= fieldset.driftdepth:
particle_ddepth = fieldset.driftdepth - particle.depth
particle.cycle_phase = 1
Expand All @@ -39,15 +59,23 @@ def ArgoVerticalMovement(particle, fieldset, time):
elif particle.cycle_phase == 3:
# Phase 3: Rising with vertical_speed until at surface
particle_ddepth -= fieldset.vertical_speed * particle.dt
particle.cycle_age += particle.dt # solve issue of not updating cycle_age during ascent
particle.cycle_age += (
particle.dt
) # solve issue of not updating cycle_age during ascent
if particle.depth + particle_ddepth >= fieldset.mindepth:
particle_ddepth = fieldset.mindepth - particle.depth
particle.temperature = math.nan # reset temperature to NaN at end of sampling cycle
particle.temperature = (
math.nan
) # reset temperature to NaN at end of sampling cycle
particle.salinity = math.nan # idem
particle.cycle_phase = 4
else:
particle.temperature = fieldset.T[time, particle.depth, particle.lat, particle.lon]
particle.salinity = fieldset.S[time, particle.depth, particle.lat, particle.lon]
particle.temperature = fieldset.T[
time, particle.depth, particle.lat, particle.lon
]
particle.salinity = fieldset.S[
time, particle.depth, particle.lat, particle.lon
]

elif particle.cycle_phase == 4:
# Phase 4: Transmitting at surface until cycletime is reached
Expand Down Expand Up @@ -84,39 +112,78 @@ class ArgoParticle(JITParticle):
time = argo_time

# Create and execute argo particles
argoset = ParticleSet(fieldset=fieldset, pclass=ArgoParticle, lon=lon, lat=lat, depth=np.repeat(fieldset.mindepth,len(time)), time=time)
argo_output_file = argoset.ParticleFile(name=os.path.join("results","Argos.zarr"), outputdt=timedelta(minutes=5), chunks=(1,500))
argoset = ParticleSet(
fieldset=fieldset,
pclass=ArgoParticle,
lon=lon,
lat=lat,
depth=np.repeat(fieldset.mindepth, len(time)),
time=time,
)
argo_output_file = argoset.ParticleFile(
name=os.path.join("results", "Argos.zarr"),
outputdt=timedelta(minutes=5),
chunks=(1, 500),
)
fieldset_endtime = fieldset.time_origin.fulltime(fieldset.U.grid.time_full[-1])
argo_endtime = np.array((datetime.datetime.strptime(config.requested_ship_time["start"],"%Y-%m-%dT%H:%M:%S") + timedelta(weeks=6))).astype('datetime64[ms]')
argo_endtime = np.array(
(
datetime.datetime.strptime(
config.requested_ship_time["start"], "%Y-%m-%dT%H:%M:%S"
)
+ timedelta(weeks=6)
)
).astype("datetime64[ms]")

argoset.execute(
[ArgoVerticalMovement, AdvectionRK4, KeepAtSurface, CheckError], # list of kernels to be executed
endtime=min(fieldset_endtime, argo_endtime), dt=timedelta(minutes=5),
output_file=argo_output_file
[
ArgoVerticalMovement,
AdvectionRK4,
KeepAtSurface,
CheckError,
], # list of kernels to be executed
endtime=min(fieldset_endtime, argo_endtime),
dt=timedelta(minutes=5),
output_file=argo_output_file,
)


def create_argo_fieldset(config):
'''Creates fieldset from netcdf files for argo floats, returns fieldset with negative depth values'''
"""
Create a fieldset from netcdf files for argo floats, return fieldset with negative depth values.
:param config: The cruise configuration.
:returns: The fieldset.
"""
datadirname = os.path.dirname(__file__)
filenames = {
"U": os.path.join(datadirname, "argodata_UV.nc"),
"V": os.path.join(datadirname, "argodata_UV.nc"),
"S": os.path.join(datadirname, "argodata_S.nc"),
"T": os.path.join(datadirname, "argodata_T.nc")}
variables = {'U': 'uo', 'V': 'vo', 'S': 'so', 'T': 'thetao'}
dimensions = {'lon': 'longitude', 'lat': 'latitude', 'time': 'time', 'depth': 'depth'}
"T": os.path.join(datadirname, "argodata_T.nc"),
}
variables = {"U": "uo", "V": "vo", "S": "so", "T": "thetao"}
dimensions = {
"lon": "longitude",
"lat": "latitude",
"time": "time",
"depth": "depth",
}

# create the fieldset and set interpolation methods
fieldset = FieldSet.from_netcdf(filenames, variables, dimensions, allow_time_extrapolation=False)
fieldset = FieldSet.from_netcdf(
filenames, variables, dimensions, allow_time_extrapolation=False
)
fieldset.T.interp_method = "linear_invdist_land_tracer"
for g in fieldset.gridset.grids:
if max(g.depth) > 0:
g.depth = -g.depth # make depth negative
fieldset.mindepth = -fieldset.U.depth[0] # uppermost layer in the hydrodynamic data
fieldset.add_constant('driftdepth', config.argo_characteristics["driftdepth"])
fieldset.add_constant('maxdepth', config.argo_characteristics["maxdepth"])
fieldset.add_constant('vertical_speed', config.argo_characteristics["vertical_speed"])
fieldset.add_constant('cycle_days', config.argo_characteristics["cycle_days"])
fieldset.add_constant('drift_days', config.argo_characteristics["drift_days"])
fieldset.add_constant("driftdepth", config.argo_characteristics["driftdepth"])
fieldset.add_constant("maxdepth", config.argo_characteristics["maxdepth"])
fieldset.add_constant(
"vertical_speed", config.argo_characteristics["vertical_speed"]
)
fieldset.add_constant("cycle_days", config.argo_characteristics["cycle_days"])
fieldset.add_constant("drift_days", config.argo_characteristics["drift_days"])
return fieldset
14 changes: 11 additions & 3 deletions virtual_ship/costs.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
"""costs function."""


def costs(config, total_time):
'''Calculates cost of the virtual ship (in US$)'''
"""
Calculate the cost of the virtual ship (in US$).
:param config: The cruise configuration.
:param total_time: Time cruised in seconds.
:returns: The calculated cost of the cruise.
"""
ship_cost_per_day = 30000
drifter_deploy_cost = 2500
argo_deploy_cost = 15000

ship_cost = ship_cost_per_day/24 * total_time//3600
ship_cost = ship_cost_per_day / 24 * total_time // 3600
argo_cost = len(config.argo_deploylocations) * argo_deploy_cost
drifter_cost = len(config.drifter_deploylocations) * drifter_deploy_cost

cost = ship_cost + argo_cost + drifter_cost
return cost
Loading

0 comments on commit a4444e6

Please sign in to comment.