diff --git a/.clang-format b/.clang-format index c260d60..da1c3e6 100644 --- a/.clang-format +++ b/.clang-format @@ -1,9 +1,9 @@ # Use clang-format -dump-config -style=google to get the base configuration --- Language: Cpp -AccessModifierOffset: -2 # MARK: Adjustable +AccessModifierOffset: -2 # MARK: Adjustable AlignAfterOpenBracket: BlockIndent -AlignArrayOfStructures: None # MARK: Adjustable +AlignArrayOfStructures: None # MARK: Adjustable AlignConsecutiveAssignments: Enabled: false AcrossEmptyLines: false @@ -31,7 +31,7 @@ AlignConsecutiveMacros: AlignEscapedNewlines: Left AlignOperands: DontAlign AlignTrailingComments: - Kind: Never # MARK: Adjustable + Kind: Never # MARK: Adjustable OverEmptyLines: 0 AllowAllArgumentsOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true @@ -78,11 +78,11 @@ BreakBeforeTernaryOperators: true BreakConstructorInitializers: BeforeColon BreakInheritanceList: BeforeColon BreakStringLiterals: false -ColumnLimit: 99 # MARK: Adjustable +ColumnLimit: 99 # MARK: Adjustable CommentPragmas: "^ IWYU pragma:" CompactNamespaces: false -ConstructorInitializerIndentWidth: 4 # MARK: Adjustable -ContinuationIndentWidth: 2 # MARK: Adjustable +ConstructorInitializerIndentWidth: 4 # MARK: Adjustable +ContinuationIndentWidth: 2 # MARK: Adjustable Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false @@ -122,7 +122,7 @@ IndentExternBlock: AfterExternBlock IndentGotoLabels: true IndentPPDirectives: None IndentRequiresClause: true -IndentWidth: 2 # MARK: Adjustable +IndentWidth: 4 # MARK: Adjustable IndentWrappedFunctionNames: false InsertBraces: false InsertNewlineAtEOF: false @@ -191,14 +191,14 @@ RawStringFormats: CanonicalDelimiter: pb BasedOnStyle: google ReferenceAlignment: Pointer -ReflowComments: false # MARK: Adjustable +ReflowComments: false # MARK: Adjustable RemoveBracesLLVM: false RemoveSemicolon: false RequiresClausePosition: OwnLine RequiresExpressionIndentation: OuterScope SeparateDefinitionBlocks: Leave ShortNamespaceLines: 1 -SortIncludes: Never # MARK: Adjustable +SortIncludes: Never # MARK: Adjustable SortJavaStaticImport: Before SortUsingDeclarations: LexicographicNumeric SpaceAfterCStyleCast: false @@ -248,4 +248,4 @@ WhitespaceSensitiveMacros: - CF_SWIFT_NAME - NS_SWIFT_NAME - PP_STRINGIZE - - STRINGIZE \ No newline at end of file + - STRINGIZE diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d555dee --- /dev/null +++ b/.dockerignore @@ -0,0 +1,22 @@ +# Ignore everything +* + +# Allow files and directories +!pyproject.toml +!setup.py +!/src/nzthermo/ +!/src/include/ +!/src/lib/ +!/tests/ +!/.git/ +# !/src + +# Ignore unnecessary files inside allowed directories +# This should go after the allowed directories +# **/*~ +**/*.pyc +**/_version.py +**/__pycache__/ +**/*.so +# **/.DS_Store +# **/Thumbs.db \ No newline at end of file diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml index c6f9bde..8b1f6aa 100644 --- a/.github/workflows/python-app.yml +++ b/.github/workflows/python-app.yml @@ -5,34 +5,32 @@ name: Python application on: push: - branches: [ "master" ] + branches: ["master"] pull_request: - branches: [ "master" ] + branches: ["master"] permissions: contents: read jobs: build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v3 - with: - python-version: "3.11" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.dev.txt - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - ruff check . --exit-zero - - name: Test with pytest - run: | - python setup.py build_ext --inplace --coverage - coverage run -m pytest - coverage report -m + - uses: actions/checkout@v4 + - name: Set up Python 3.11 + uses: actions/setup-python@v3 + with: + python-version: "3.11" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.dev.txt + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + ruff check . --exit-zero + - name: Test with pytest + run: | + python setup.py build_ext --inplace --coverage + coverage run -m pytest + coverage report -m diff --git a/.gitignore b/.gitignore index 8775833..46094f1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,13 +2,15 @@ .venv/ build/ **/__pycache__/ -**/*.pyc -**/*.so -src/nzthermo/*.c -.egg/ +*.pyc +*.so *.egg-info/ +*.dist-info/ +src/**/_ufunc.cpp +src/**/_core.cpp +src/**/_version.py +.egg/ .vscode/ .coverage .reports/ -.trash/ -src/nzthermo/_version.py \ No newline at end of file +.trash/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..392c847 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,64 @@ +cmake_minimum_required(VERSION 3.14) +project(libthermo) + +# # Set the compiler options +# # The --coverage compiler flag is an alternative to -fprofile-arcs -ftest-coverage for recent version of gcc. +# # In versions 3.13 and later of cmake, the target_link_libraries command can be +# # removed and add_link_options("--coverage") added after the add_compile_options command. +# # GoogleTest requires at least C++14 +# set(CMAKE_CXX_STANDARD 20) +# set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_REQUIRED_FLAGS -fconcepts) +# set(CMAKE_CXX_FLAGS "-g -O0 -Wall --coverage") +# set(CMAKE_C_FLAGS --coverage) + +# include(FetchContent) +# FetchContent_Declare( +# googletest +# URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +# ) + +# # For Windows: Prevent overriding the parent project's compiler/linker settings +# set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +# FetchContent_MakeAvailable(googletest) +add_compile_options( +"$<$:-Ofast;-DNDEBUG;-fconcepts;-std=c++2a;-march=native;-fpic;-ftree-vectorize>" +) +# # ------------------------------------------------------------------------------------------------- +# # GTest +# # ------------------------------------------------------------------------------------------------- +# enable_testing() +include_directories(src/include/) +add_executable( + slac_test + # src/lib/_C.cpp + src/lib/functional.cpp + # src/include/_C.hpp + # src/include/common.hpp + src/include/functional.hpp +) + +# # link everything together +# target_link_libraries(slac_test GTest::gtest_main) + +# if(CMAKE_BUILD_TYPE STREQUAL "DEBUG") +# add_test( +# NAME slac_test +# COMMAND slac_test --gtest_output=xml:gtest-output.xml +# ) +# add_test( +# NAME Coverage +# COMMAND gcovr --exclude-directories build/CMakeFiles/slac_test.dir/src/lib/tests --cobertura coverage.cobertura.xml +# WORKING_DIRECTORY .. +# ) +# else() +# add_test( +# NAME slac_test +# COMMAND slac_test --gtest_output=xml:/app/gtest-output.xml +# ) +# add_test( +# NAME Coverage +# COMMAND gcovr --exclude-directories build/CMakeFiles/slac_test.dir/src/lib/tests --cobertura coverage.cobertura.xml +# WORKING_DIRECTORY .. +# ) +# endif() diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..452557b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +# syntax=docker/dockerfile:1 + +# ................................................................................................. +# FROM python:3.10.14 AS py310 +# USER root +# WORKDIR / + +# ENV PATH="/opt/venv/bin:$PATH" +# RUN python3 -m venv /opt/venv +# COPY tests/requirements.txt . +# RUN pip install --no-cache-dir -r requirements.txt + +# COPY . . +# ENV NZTHERMO_BUILD_COVERAGE 1 +# RUN pip install --no-cache-dir --no-deps --upgrade --target src/ . + +# USER 1001 + +# ................................................................................................. +FROM python:3.11.9 AS py311 +USER root +WORKDIR / + +ENV PATH="/opt/venv/bin:$PATH" +RUN python3 -m venv /opt/venv +COPY tests/requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . +ENV NZTHERMO_BUILD_COVERAGE 1 +RUN pip install --no-cache-dir --no-deps --upgrade --target src/ . \ + && pytest tests + +USER 1001 + +# ................................................................................................. +FROM python:3.12.3 AS py312 +USER root +WORKDIR / + +ENV PATH="/opt/venv/bin:$PATH" +RUN python3 -m venv /opt/venv +COPY tests/requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . +ENV NZTHERMO_BUILD_COVERAGE 1 +RUN pip install --no-cache-dir --no-deps --upgrade --target src/ . \ + && pytest tests + +USER 1001 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d3360b8 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ + +clean: + rm -rf dist/ build/ .pytest_cache/ .coverage *.egg-info/ src/*.egg-info/ src/nzthermo/_version.py src/nzthermo/*.so src/nzthermo/__pycache__/ \ No newline at end of file diff --git a/c.ipynb b/c.ipynb new file mode 100644 index 0000000..dccc067 --- /dev/null +++ b/c.ipynb @@ -0,0 +1,971 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext cython" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 0 31]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + "\n", + " \n", + " Cython: _cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06.pyx\n", + " \n", + "\n", + "\n", + "

Generated by Cython 3.0.10

\n", + "

\n", + " Yellow lines hint at Python interaction.
\n", + " Click on a line that starts with a \"+\" to see the C code that Cython generated for it.\n", + "

\n", + "
+01: # distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION
\n", + "
  __pyx_t_7 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 1, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_7);\n",
+       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_7) < 0) __PYX_ERR(0, 1, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
+       "
 02: #distutils: extra_compile_args = -fopenmp
\n", + "
 03: #distutils: extra_link_args = -fopenmp
\n", + "
 04: # cython: language_level=3
\n", + "
 05: # cython: boundscheck=False
\n", + "
 06: # cython: wraparound=False
\n", + "
 07: # cython: nonecheck=False
\n", + "
 08: # cython: cdivision=True
\n", + "
 09: cimport cython
\n", + "
 10: import cython
\n", + "
 11: cimport numpy as np
\n", + "
+12: import numpy as np
\n", + "
  __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_n_s_numpy, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_2) < 0) __PYX_ERR(0, 12, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "
+13: np.import_array()
\n", + "
  __pyx_t_3 = __pyx_f_5numpy_import_array(); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(0, 13, __pyx_L1_error)\n",
+       "
 14: 
\n", + "
 15: 
\n", + "
+16: cdef class unixtime:
\n", + "
struct __pyx_obj_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime {\n",
+       "  PyObject_HEAD\n",
+       "  struct __pyx_vtabstruct_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *__pyx_vtab;\n",
+       "  PyArrayObject *values;\n",
+       "};\n",
+       "\n",
+       "\n",
+       "\n",
+       "struct __pyx_vtabstruct_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime {\n",
+       "  PyObject *(*years)(struct __pyx_obj_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *, int __pyx_skip_dispatch);\n",
+       "};\n",
+       "static struct __pyx_vtabstruct_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *__pyx_vtabptr_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime;\n",
+       "
 17: 
\n", + "
 18:     cdef np.ndarray values
\n", + "
 19: 
\n", + "
+20:     def __cinit__(unixtime self, np.ndarray[np.int_t, ndim=1] values):
\n", + "
/* Python wrapper */\n",
+       "static int __pyx_pw_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/\n",
+       "static int __pyx_pw_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_1__cinit__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {\n",
+       "  PyArrayObject *__pyx_v_values = 0;\n",
+       "  CYTHON_UNUSED Py_ssize_t __pyx_nargs;\n",
+       "  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;\n",
+       "  int __pyx_r;\n",
+       "  __Pyx_RefNannyDeclarations\n",
+       "  __Pyx_RefNannySetupContext(\"__cinit__ (wrapper)\", 0);\n",
+       "  #if CYTHON_ASSUME_SAFE_MACROS\n",
+       "  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);\n",
+       "  #else\n",
+       "  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return -1;\n",
+       "  #endif\n",
+       "  __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs);\n",
+       "  {\n",
+       "    PyObject **__pyx_pyargnames[] = {&__pyx_n_s_values,0};\n",
+       "  PyObject* values[1] = {0};\n",
+       "    if (__pyx_kwds) {\n",
+       "      Py_ssize_t kw_args;\n",
+       "      switch (__pyx_nargs) {\n",
+       "        case  1: values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0);\n",
+       "        CYTHON_FALLTHROUGH;\n",
+       "        case  0: break;\n",
+       "        default: goto __pyx_L5_argtuple_error;\n",
+       "      }\n",
+       "      kw_args = __Pyx_NumKwargs_VARARGS(__pyx_kwds);\n",
+       "      switch (__pyx_nargs) {\n",
+       "        case  0:\n",
+       "        if (likely((values[0] = __Pyx_GetKwValue_VARARGS(__pyx_kwds, __pyx_kwvalues, __pyx_n_s_values)) != 0)) {\n",
+       "          (void)__Pyx_Arg_NewRef_VARARGS(values[0]);\n",
+       "          kw_args--;\n",
+       "        }\n",
+       "        else if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 20, __pyx_L3_error)\n",
+       "        else goto __pyx_L5_argtuple_error;\n",
+       "      }\n",
+       "      if (unlikely(kw_args > 0)) {\n",
+       "        const Py_ssize_t kwd_pos_args = __pyx_nargs;\n",
+       "        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values + 0, kwd_pos_args, \"__cinit__\") < 0)) __PYX_ERR(0, 20, __pyx_L3_error)\n",
+       "      }\n",
+       "    } else if (unlikely(__pyx_nargs != 1)) {\n",
+       "      goto __pyx_L5_argtuple_error;\n",
+       "    } else {\n",
+       "      values[0] = __Pyx_Arg_VARARGS(__pyx_args, 0);\n",
+       "    }\n",
+       "    __pyx_v_values = ((PyArrayObject *)values[0]);\n",
+       "  }\n",
+       "  goto __pyx_L6_skip;\n",
+       "  __pyx_L5_argtuple_error:;\n",
+       "  __Pyx_RaiseArgtupleInvalid(\"__cinit__\", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 20, __pyx_L3_error)\n",
+       "  __pyx_L6_skip:;\n",
+       "  goto __pyx_L4_argument_unpacking_done;\n",
+       "  __pyx_L3_error:;\n",
+       "  {\n",
+       "    Py_ssize_t __pyx_temp;\n",
+       "    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {\n",
+       "      __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]);\n",
+       "    }\n",
+       "  }\n",
+       "  __Pyx_AddTraceback(\"_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06.unixtime.__cinit__\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return -1;\n",
+       "  __pyx_L4_argument_unpacking_done:;\n",
+       "  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_values), __pyx_ptype_5numpy_ndarray, 1, \"values\", 0))) __PYX_ERR(0, 20, __pyx_L1_error)\n",
+       "  __pyx_r = __pyx_pf_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime___cinit__(((struct __pyx_obj_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *)__pyx_v_self), __pyx_v_values);\n",
+       "  int __pyx_lineno = 0;\n",
+       "  const char *__pyx_filename = NULL;\n",
+       "  int __pyx_clineno = 0;\n",
+       "\n",
+       "  /* function exit code */\n",
+       "  goto __pyx_L0;\n",
+       "  __pyx_L1_error:;\n",
+       "  __pyx_r = -1;\n",
+       "  __pyx_L0:;\n",
+       "  {\n",
+       "    Py_ssize_t __pyx_temp;\n",
+       "    for (__pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {\n",
+       "      __Pyx_Arg_XDECREF_VARARGS(values[__pyx_temp]);\n",
+       "    }\n",
+       "  }\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return __pyx_r;\n",
+       "}\n",
+       "\n",
+       "static int __pyx_pf_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime___cinit__(struct __pyx_obj_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *__pyx_v_self, PyArrayObject *__pyx_v_values) {\n",
+       "  __Pyx_LocalBuf_ND __pyx_pybuffernd_values;\n",
+       "  __Pyx_Buffer __pyx_pybuffer_values;\n",
+       "  int __pyx_r;\n",
+       "  __pyx_pybuffer_values.pybuffer.buf = NULL;\n",
+       "  __pyx_pybuffer_values.refcount = 0;\n",
+       "  __pyx_pybuffernd_values.data = NULL;\n",
+       "  __pyx_pybuffernd_values.rcbuffer = &__pyx_pybuffer_values;\n",
+       "  {\n",
+       "    __Pyx_BufFmt_StackElem __pyx_stack[1];\n",
+       "    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_values.rcbuffer->pybuffer, (PyObject*)__pyx_v_values, &__Pyx_TypeInfo_nn___pyx_t_5numpy_int_t, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) __PYX_ERR(0, 20, __pyx_L1_error)\n",
+       "  }\n",
+       "  __pyx_pybuffernd_values.diminfo[0].strides = __pyx_pybuffernd_values.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_values.diminfo[0].shape = __pyx_pybuffernd_values.rcbuffer->pybuffer.shape[0];\n",
+       "/* … */\n",
+       "  /* function exit code */\n",
+       "  __pyx_r = 0;\n",
+       "  goto __pyx_L0;\n",
+       "  __pyx_L1_error:;\n",
+       "  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;\n",
+       "    __Pyx_PyThreadState_declare\n",
+       "    __Pyx_PyThreadState_assign\n",
+       "    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);\n",
+       "    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_values.rcbuffer->pybuffer);\n",
+       "  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}\n",
+       "  __Pyx_AddTraceback(\"_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06.unixtime.__cinit__\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
+       "  __pyx_r = -1;\n",
+       "  goto __pyx_L2;\n",
+       "  __pyx_L0:;\n",
+       "  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_values.rcbuffer->pybuffer);\n",
+       "  __pyx_L2:;\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return __pyx_r;\n",
+       "}\n",
+       "
+21:         self.values = values
\n", + "
  __Pyx_INCREF((PyObject *)__pyx_v_values);\n",
+       "  __Pyx_GIVEREF((PyObject *)__pyx_v_values);\n",
+       "  __Pyx_GOTREF((PyObject *)__pyx_v_self->values);\n",
+       "  __Pyx_DECREF((PyObject *)__pyx_v_self->values);\n",
+       "  __pyx_v_self->values = ((PyArrayObject *)__pyx_v_values);\n",
+       "
 22: 
\n", + "
+23:     cpdef years(unixtime self):
\n", + "
static PyObject *__pyx_pw_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_3years(PyObject *__pyx_v_self, \n",
+       "#if CYTHON_METH_FASTCALL\n",
+       "PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds\n",
+       "#else\n",
+       "PyObject *__pyx_args, PyObject *__pyx_kwds\n",
+       "#endif\n",
+       "); /*proto*/\n",
+       "static PyObject *__pyx_f_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_years(struct __pyx_obj_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *__pyx_v_self, int __pyx_skip_dispatch) {\n",
+       "  PyObject *__pyx_r = NULL;\n",
+       "  /* Check if called by wrapper */\n",
+       "  if (unlikely(__pyx_skip_dispatch)) ;\n",
+       "  /* Check if overridden in Python */\n",
+       "  else if (unlikely((Py_TYPE(((PyObject *)__pyx_v_self))->tp_dictoffset != 0) || __Pyx_PyType_HasFeature(Py_TYPE(((PyObject *)__pyx_v_self)), (Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_HEAPTYPE)))) {\n",
+       "    #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS\n",
+       "    static PY_UINT64_T __pyx_tp_dict_version = __PYX_DICT_VERSION_INIT, __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT;\n",
+       "    if (unlikely(!__Pyx_object_dict_version_matches(((PyObject *)__pyx_v_self), __pyx_tp_dict_version, __pyx_obj_dict_version))) {\n",
+       "      PY_UINT64_T __pyx_typedict_guard = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self));\n",
+       "      #endif\n",
+       "      __pyx_t_1 = __Pyx_PyObject_GetAttrStr(((PyObject *)__pyx_v_self), __pyx_n_s_years); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 23, __pyx_L1_error)\n",
+       "      __Pyx_GOTREF(__pyx_t_1);\n",
+       "      if (!__Pyx_IsSameCFunction(__pyx_t_1, (void*) __pyx_pw_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_3years)) {\n",
+       "        __Pyx_XDECREF(__pyx_r);\n",
+       "        __Pyx_INCREF(__pyx_t_1);\n",
+       "        __pyx_t_3 = __pyx_t_1; __pyx_t_4 = NULL;\n",
+       "        __pyx_t_5 = 0;\n",
+       "        #if CYTHON_UNPACK_METHODS\n",
+       "        if (unlikely(PyMethod_Check(__pyx_t_3))) {\n",
+       "          __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3);\n",
+       "          if (likely(__pyx_t_4)) {\n",
+       "            PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);\n",
+       "            __Pyx_INCREF(__pyx_t_4);\n",
+       "            __Pyx_INCREF(function);\n",
+       "            __Pyx_DECREF_SET(__pyx_t_3, function);\n",
+       "            __pyx_t_5 = 1;\n",
+       "          }\n",
+       "        }\n",
+       "        #endif\n",
+       "        {\n",
+       "          PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL};\n",
+       "          __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+1-__pyx_t_5, 0+__pyx_t_5);\n",
+       "          __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;\n",
+       "          if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error)\n",
+       "          __Pyx_GOTREF(__pyx_t_2);\n",
+       "          __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;\n",
+       "        }\n",
+       "        __pyx_r = __pyx_t_2;\n",
+       "        __pyx_t_2 = 0;\n",
+       "        __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "        goto __pyx_L0;\n",
+       "      }\n",
+       "      #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS\n",
+       "      __pyx_tp_dict_version = __Pyx_get_tp_dict_version(((PyObject *)__pyx_v_self));\n",
+       "      __pyx_obj_dict_version = __Pyx_get_object_dict_version(((PyObject *)__pyx_v_self));\n",
+       "      if (unlikely(__pyx_typedict_guard != __pyx_tp_dict_version)) {\n",
+       "        __pyx_tp_dict_version = __pyx_obj_dict_version = __PYX_DICT_VERSION_INIT;\n",
+       "      }\n",
+       "      #endif\n",
+       "      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;\n",
+       "      #if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS\n",
+       "    }\n",
+       "    #endif\n",
+       "  }\n",
+       "/* … */\n",
+       "  /* function exit code */\n",
+       "  __pyx_L1_error:;\n",
+       "  __Pyx_XDECREF(__pyx_t_1);\n",
+       "  __Pyx_XDECREF(__pyx_t_2);\n",
+       "  __Pyx_XDECREF(__pyx_t_3);\n",
+       "  __Pyx_XDECREF(__pyx_t_4);\n",
+       "  __Pyx_AddTraceback(\"_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06.unixtime.years\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
+       "  __pyx_r = 0;\n",
+       "  __pyx_L0:;\n",
+       "  __Pyx_XGIVEREF(__pyx_r);\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return __pyx_r;\n",
+       "}\n",
+       "\n",
+       "/* Python wrapper */\n",
+       "static PyObject *__pyx_pw_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_3years(PyObject *__pyx_v_self, \n",
+       "#if CYTHON_METH_FASTCALL\n",
+       "PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds\n",
+       "#else\n",
+       "PyObject *__pyx_args, PyObject *__pyx_kwds\n",
+       "#endif\n",
+       "); /*proto*/\n",
+       "static PyMethodDef __pyx_mdef_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_3years = {\"years\", (PyCFunction)(void*)(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_3years, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0};\n",
+       "static PyObject *__pyx_pw_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_3years(PyObject *__pyx_v_self, \n",
+       "#if CYTHON_METH_FASTCALL\n",
+       "PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds\n",
+       "#else\n",
+       "PyObject *__pyx_args, PyObject *__pyx_kwds\n",
+       "#endif\n",
+       ") {\n",
+       "  #if !CYTHON_METH_FASTCALL\n",
+       "  CYTHON_UNUSED Py_ssize_t __pyx_nargs;\n",
+       "  #endif\n",
+       "  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;\n",
+       "  PyObject *__pyx_r = 0;\n",
+       "  __Pyx_RefNannyDeclarations\n",
+       "  __Pyx_RefNannySetupContext(\"years (wrapper)\", 0);\n",
+       "  #if !CYTHON_METH_FASTCALL\n",
+       "  #if CYTHON_ASSUME_SAFE_MACROS\n",
+       "  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);\n",
+       "  #else\n",
+       "  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;\n",
+       "  #endif\n",
+       "  #endif\n",
+       "  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);\n",
+       "  if (unlikely(__pyx_nargs > 0)) {\n",
+       "    __Pyx_RaiseArgtupleInvalid(\"years\", 1, 0, 0, __pyx_nargs); return NULL;}\n",
+       "  if (unlikely(__pyx_kwds) && __Pyx_NumKwargs_FASTCALL(__pyx_kwds) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, \"years\", 0))) return NULL;\n",
+       "  __pyx_r = __pyx_pf_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_2years(((struct __pyx_obj_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *)__pyx_v_self));\n",
+       "\n",
+       "  /* function exit code */\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return __pyx_r;\n",
+       "}\n",
+       "\n",
+       "static PyObject *__pyx_pf_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_2years(struct __pyx_obj_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime *__pyx_v_self) {\n",
+       "  PyObject *__pyx_r = NULL;\n",
+       "  __Pyx_XDECREF(__pyx_r);\n",
+       "  __pyx_t_1 = __pyx_f_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_years(__pyx_v_self, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 23, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_r = __pyx_t_1;\n",
+       "  __pyx_t_1 = 0;\n",
+       "  goto __pyx_L0;\n",
+       "\n",
+       "  /* function exit code */\n",
+       "  __pyx_L1_error:;\n",
+       "  __Pyx_XDECREF(__pyx_t_1);\n",
+       "  __Pyx_AddTraceback(\"_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06.unixtime.years\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
+       "  __pyx_r = NULL;\n",
+       "  __pyx_L0:;\n",
+       "  __Pyx_XGIVEREF(__pyx_r);\n",
+       "  __Pyx_RefNannyFinishContext();\n",
+       "  return __pyx_r;\n",
+       "}\n",
+       "/* … */\n",
+       "  __pyx_tuple__4 = PyTuple_Pack(1, __pyx_n_s_self); if (unlikely(!__pyx_tuple__4)) __PYX_ERR(0, 23, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_tuple__4);\n",
+       "  __Pyx_GIVEREF(__pyx_tuple__4);\n",
+       "/* … */\n",
+       "  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_8unixtime_3years, __Pyx_CYFUNCTION_CCLASS, __pyx_n_s_unixtime_years, NULL, __pyx_n_s_cython_magic_849b2be7ec3b5ecc6e, __pyx_d, ((PyObject *)__pyx_codeobj__5)); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  if (__Pyx_SetItemOnTypeDict((PyObject *)__pyx_ptype_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime, __pyx_n_s_years, __pyx_t_2) < 0) __PYX_ERR(0, 23, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  PyType_Modified(__pyx_ptype_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime);\n",
+       "  __pyx_codeobj__5 = (PyObject*)__Pyx_PyCode_New(1, 0, 0, 1, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__4, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_home_leaver_cache_ipython_cytho, __pyx_n_s_years, 23, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__5)) __PYX_ERR(0, 23, __pyx_L1_error)\n",
+       "
+24:         return self.values // 31556952
\n", + "
  __Pyx_XDECREF(__pyx_r);\n",
+       "  __pyx_t_1 = PyNumber_FloorDivide(((PyObject *)__pyx_v_self->values), __pyx_int_31556952); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 24, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_1);\n",
+       "  __pyx_r = __pyx_t_1;\n",
+       "  __pyx_t_1 = 0;\n",
+       "  goto __pyx_L0;\n",
+       "
 25: 
\n", + "
 26: 
\n", + "
 27: 
\n", + "
 28: 
\n", + "
 29: 
\n", + "
 30: 
\n", + "
 31: 
\n", + "
 32: 
\n", + "
 33:     # def __repr__(self):
\n", + "
 34:     #     return f"timeseries({self.dt})"
\n", + "
 35: 
\n", + "
+36: dt = np.array(["1970-01-01T00:00:00.000000000", "1970-01-01T00:00:01.000000000"], dtype=np.datetime64)
\n", + "
  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_array); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_4);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __pyx_t_2 = PyList_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_INCREF(__pyx_kp_u_1970_01_01T00_00_00_000000000);\n",
+       "  __Pyx_GIVEREF(__pyx_kp_u_1970_01_01T00_00_00_000000000);\n",
+       "  if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_kp_u_1970_01_01T00_00_00_000000000)) __PYX_ERR(0, 36, __pyx_L1_error);\n",
+       "  __Pyx_INCREF(__pyx_kp_u_1970_01_01T00_00_01_000000000);\n",
+       "  __Pyx_GIVEREF(__pyx_kp_u_1970_01_01T00_00_01_000000000);\n",
+       "  if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_kp_u_1970_01_01T00_00_01_000000000)) __PYX_ERR(0, 36, __pyx_L1_error);\n",
+       "  __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_5);\n",
+       "  __Pyx_GIVEREF(__pyx_t_2);\n",
+       "  if (__Pyx_PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error);\n",
+       "  __pyx_t_2 = 0;\n",
+       "  __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_6);\n",
+       "  __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_datetime64); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_7);\n",
+       "  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;\n",
+       "  if (PyDict_SetItem(__pyx_t_2, __pyx_n_s_dtype, __pyx_t_7) < 0) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
+       "  __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_5, __pyx_t_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_7);\n",
+       "  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_dt, __pyx_t_7) < 0) __PYX_ERR(0, 36, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
+       "
+37: ts = unixtime(dt.astype('int64'))
\n", + "
  __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_n_s_dt); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 37, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_7);\n",
+       "  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_n_s_astype); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
+       "  __pyx_t_7 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_tuple__9, NULL); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 37, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_7);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __pyx_t_2 = __Pyx_PyObject_CallOneArg(((PyObject *)__pyx_ptype_54_cython_magic_849b2be7ec3b5ecc6e389fb8a681e42f5c86ed06_unixtime), __pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
+       "  if (PyDict_SetItem(__pyx_d, __pyx_n_s_ts, __pyx_t_2) < 0) __PYX_ERR(0, 37, __pyx_L1_error)\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "
+38: print(ts.years())
\n", + "
  __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_n_s_ts); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 38, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_years); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 38, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_7);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __pyx_t_2 = __Pyx_PyObject_CallNoArg(__pyx_t_7); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 38, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_2);\n",
+       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
+       "  __pyx_t_7 = __Pyx_PyObject_CallOneArg(__pyx_builtin_print, __pyx_t_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 38, __pyx_L1_error)\n",
+       "  __Pyx_GOTREF(__pyx_t_7);\n",
+       "  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;\n",
+       "  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;\n",
+       "
" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%cython --annotate\n", + "# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION\n", + "#distutils: extra_compile_args = -fopenmp\n", + "#distutils: extra_link_args = -fopenmp\n", + "# cython: language_level=3\n", + "# cython: boundscheck=False\n", + "# cython: wraparound=False\n", + "# cython: nonecheck=False\n", + "# cython: cdivision=True\n", + "cimport cython\n", + "import cython\n", + "cimport numpy as np\n", + "import numpy as np\n", + "np.import_array()\n", + "\n", + "\n", + "cdef class unixtime:\n", + " \n", + " cdef np.ndarray values\n", + " \n", + " def __cinit__(unixtime self, np.ndarray[np.int_t, ndim=1] values):\n", + " self.values = values\n", + " \n", + " cpdef years(unixtime self):\n", + " return self.values // 31556952\n", + "\n", + " \n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + " # def __repr__(self):\n", + " # return f\"timeseries({self.dt})\"\n", + "\n", + "dt = np.array([\"1970-01-01T00:00:00.000000000\", \"1970-01-01T00:00:01.000000000\"], dtype=np.datetime64)\n", + "ts = unixtime(dt.astype('int64'))\n", + "print(ts.years())" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Timeseries(years=array([1970, 2020, 2024, 2024], dtype=uint32), months=array([1, 2, 2, 2], dtype=uint32), days=array([ 1, 29, 29, 29], dtype=uint32), hours=array([0, 0, 0, 0], dtype=uint32), minutes=array([0, 0, 0, 0], dtype=uint32), seconds=array([0, 0, 1, 0], dtype=uint32), microseconds=array([0, 0, 0, 0], dtype=uint32))\n", + "years [1970 2020 2024 2024]\n", + "months [1 2 2 2]\n", + "days [ 1 29 29 29]\n", + "hours [0 0 0 0]\n", + "delta_t [40.23467888 71.66730358 73.94523658 73.94523658]\n", + "[[1970 2020 2024 2024]\n", + " [ 1 2 2 2]\n", + " [ 1 29 29 29]\n", + " [ 0 0 0 0]\n", + " [ 0 0 0 0]\n", + " [ 0 0 1 0]\n", + " [ 0 0 0 0]]\n", + "['1970-01-01T00:00:00.000000' '2020-02-29T00:00:00.000000'\n", + " '2024-02-29T00:00:01.000000' '2024-02-29T00:00:00.000000']\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "(True, True)" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "# np.array([\"1970-01-01T00:00:00.000000000\", \"1970-01-01T00:00:01.000000000\"], dtype=np.datetime64).astype(\"datetime64[Y]\").astype(np.int64) + 1970\n", + "from typing import Self\n", + "from typing import NamedTuple\n", + "\n", + "import nzthermo as nzt\n", + "\n", + "values = np.array([\n", + " \"1970-01-01T00:00:00.000000000\",\n", + " # a leap year\n", + " \"2020-02-29T00:00:00.000000000\",\n", + " \"2024-02-29T00:00:01.000000000\",\n", + " \"2024-02-29\",\n", + " \n", + " \n", + "], dtype=\"datetime64[ns]\")\n", + "\n", + "a = nzt.timeseries(values)\n", + " \n", + "print(\n", + "f\"\"\"\n", + "{a}\n", + "years {a.years}\n", + "months {a.months}\n", + "days {a.days}\n", + "hours {a.hours}\n", + "delta_t {a.delta_t}\n", + "{np.array(a)}\n", + "{a.to_datetime64()}\n", + "\"\"\"\n", + ")\n", + "\n", + "def degrees(x: float) -> float:\n", + " return x * 180 / np.pi\n", + "\n", + "def radians(x: float) -> float:\n", + " return x * np.pi / 180\n", + "\n", + "np.testing.assert_almost_equal(degrees(radians(1)), 1)\n", + "\n", + "np.deg2rad(1) == radians(1), np.rad2deg(1) == degrees(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1716201353.765075" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import datetime\n", + "nzt.timeseries(datetime.datetime.now().timestamp())" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/notebook.ipynb b/notebook.ipynb index 7817eb8..d8622b7 100644 --- a/notebook.ipynb +++ b/notebook.ipynb @@ -43,34 +43,6 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(611.21, 611.21, 6.1365484, 6.135946000000001)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from math import exp\n", - "\n", - "from nzthermo.const import E0, T0\n", - "import nzthermo\n", - "\n", - "temperature = 273.15 + 20 # 20 degrees C\n", - "# P = E0 * exp(17.67 * (temperature - T0) / (temperature - 29.65)) # saturation vapor pressure\n", - "# P, 611.21 * exp(17.502 * (temperature - 273.15) *((temperature - 32.18)**(-1)))\n", - "E0, nzthermo.saturation_vapor_pressure(T0), 6.1121 * 1.004, 6.1115 * 1.004" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, "outputs": [], "source": [ "import gcsfs\n", @@ -92,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -484,12 +456,12 @@ " volumetric_soil_water_layer_3 (time, latitude, longitude) float32 388GB dask.array<chunksize=(1, 721, 1440), meta=np.ndarray>\n", " volumetric_soil_water_layer_4 (time, latitude, longitude) float32 388GB dask.array<chunksize=(1, 721, 1440), meta=np.ndarray>\n", " vorticity (time, level, latitude, longitude) float32 5TB dask.array<chunksize=(1, 13, 721, 1440), meta=np.ndarray>\n", - " wind_speed (time, level, latitude, longitude) float32 5TB dask.array<chunksize=(1, 13, 721, 1440), meta=np.ndarray>