diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..9133314 --- /dev/null +++ b/.env.example @@ -0,0 +1,51 @@ +# TJWater Server 环境变量配置模板 +# 复制此文件为 .env 并填写实际值 +ENVIRONMENT="local" +NETWORK_NAME="tjwater" +# ============================================ +# 安全配置 (必填) +# ============================================ + +# JWT 密钥 - 用于生成和验证 Token +# 生成方式: openssl rand -hex 32 +SECRET_KEY=your-secret-key-here-change-in-production-use-openssl-rand-hex-32 + +# 数据加密密钥 - 用于敏感数据加密 +# 生成方式: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" +ENCRYPTION_KEY= +DATABASE_ENCRYPTION_KEY="rJC2VqLg4KrlSq+DGJcYm869q4v5KB2dFAeuQTe0I50=" + +# ============================================ +# 数据库配置 (PostgreSQL) +# ============================================ +DB_NAME="tjwater" +DB_HOST="localhost" +DB_PORT="5432" +DB_USER="tjwater" +DB_PASSWORD="password" + +# ============================================ +# 数据库配置 (TimescaleDB) +# ============================================ +TIMESCALEDB_DB_NAME="tjwater" +TIMESCALEDB_DB_HOST="localhost" +TIMESCALEDB_DB_PORT="5433" +TIMESCALEDB_DB_USER="tjwater" +TIMESCALEDB_DB_PASSWORD="password" + +# ============================================ +# 元数据数据库配置 (Metadata DB) +# ============================================ +METADATA_DB_NAME="system_hub" +METADATA_DB_HOST="localhost" +METADATA_DB_PORT="5432" +METADATA_DB_USER="tjwater" +METADATA_DB_PASSWORD="password" + +# ============================================ +# Keycloak JWT (可选) +# ============================================ +KEYCLOAK_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----" +KEYCLOAK_ALGORITHM=RS256 +KEYCLOAK_AUDIENCE="account" + diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..23396a2 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,82 @@ +# Copilot Instructions for TJWater Server + +This repository contains the backend code for the TJWater Server, a water distribution network management system built with FastAPI. + +## High-Level Architecture + +The application follows a layered architecture: + +- **Entry Point**: `app/main.py` initializes the FastAPI application, database connections (PostgreSQL & TimescaleDB), and middleware. +- **API Layer**: `app/api/v1` contains the route handlers. +- **Service Layer**: `app/services` contains business logic and orchestration. +- **Infrastructure Layer**: `app/infra` handles database connections (`db`), audit logging (`audit`), and external integrations. +- **Domain Layer**: `app/domain` likely contains core domain models. +- **Native/Algorithms**: `app/native` and `app/algorithms` handle specialized water network calculations (possibly using EPANET/WNTR). + +## Build, Test, and Run Commands + +### Environment Setup + +- Dependencies are listed in `requirements.txt`. +- Configuration is managed via environment variables (see `.env.example` if available, or `app/core/config.py`). +- **Important**: Ensure `.env` is configured with correct database credentials for both PostgreSQL and TimescaleDB. + +If first time setting up, you may want to create a Conda environment: + +```bash +conda create -n server python=3.12 +conda activate server +pip install uv +uv pip install -r requirements.txt +conda install -c conda-forge pymetis +``` + +### Running the Server + +The preferred way to run the server locally is using the helper script which sets up the Python path correctly: + +```bash +conda activate server +python scripts/run_server.py +``` + +Alternatively, you can run directly with uvicorn (ensure PYTHONPATH includes the root): + +```bash +conda activate server +uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload +``` + +### Running Tests + +Use `pytest` to run tests. The `tests/conftest.py` handles path setup. + +```bash +# Run all tests +pytest + +# Run a specific test file +pytest tests/unit/test_specific_file.py + +# Run a specific test case +pytest tests/unit/test_specific_file.py::test_function_name +``` + +### Building (Optional) + +The project includes scripts to compile Python modules to `.pyd` files using Cython (see `scripts/build_pyd.py`). This is likely for distribution/performance but not required for standard development. + +## Key Conventions + +- **Async/Await**: The codebase heavily uses `async` and `await` for I/O operations, especially database interactions. +- **Database Management**: + - Connections are managed globally in `app.infra.db` and initialized in `lifespan` (app/main.py). + - Use `app.infra.db.dynamic_manager` for project-specific database connections (multi-tenancy/dynamic projects). +- **Pydantic**: extensively used for data validation and settings management. +- **Scripts**: The `scripts/` directory contains many utility scripts for maintenance, data processing, and server management. Check there before writing new operational scripts. +- **Water Network Modeling**: Interactions with water network models often involve `epanet` or `wntr` libraries. Be aware of domain-specific terminology (nodes, links, junctions, tanks). + +## Code Style + +- Follow standard PEP 8 guidelines. +- No specific linter configuration was found, so default to standard Python formatting. diff --git a/.gitignore b/.gitignore index 5d783af..10754c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ -*.pyc -.env db_inp/ temp/ data/ +build/ +*.pyc +.env *.dump +.vscode/ +app/algorithms/health/model/my_survival_forest_model_quxi.joblib diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index e586700..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "debugpy", - "request": "launch", - "name": "Debug Uvicorn", - "module": "uvicorn", - "args": [ - "main:app", - "--host", - "0.0.0.0", - "--port", - "8000", - "--workers", - "1" - ] - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 4258f47..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "cSpell.words": [ - "Fastapi" - ] -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7182cac --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM continuumio/miniconda3:latest + +WORKDIR /app + +# 安装 Python 3.12 和 pymetis (通过 conda-forge 避免编译问题) +RUN conda install -y -c conda-forge python=3.12 pymetis && \ + conda clean -afy + +COPY requirements.txt . +RUN pip install uv +RUN uv pip install --no-cache-dir -r requirements.txt + +# 将代码放入子目录 'app',将数据放入子目录 'db_inp' +# 这样临时文件默认会生成在 /app 下,而代码在 /app/app 下,实现了分离 +COPY app ./app +COPY db_inp ./db_inp +COPY temp ./temp +COPY .env . + +# 设置 PYTHONPATH 以便 uvicorn 找到 app 模块 +ENV PYTHONPATH=/app + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"] diff --git a/ReadMe.txt b/ReadMe.txt deleted file mode 100644 index 50771f4..0000000 --- a/ReadMe.txt +++ /dev/null @@ -1,4 +0,0 @@ -当前 适配 szh 项目的分支 是 dingsu/szh - -Binary 适配的是 代码 中dingsu/szh 的部分 -当前只是把 API目录(也就是TJNetwork的部分)加密了 diff --git a/api/__init__.cp312-win_amd64.pyd b/api/__init__.cp312-win_amd64.pyd deleted file mode 100644 index f89c301..0000000 Binary files a/api/__init__.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/batch_api.cp312-win_amd64.pyd b/api/batch_api.cp312-win_amd64.pyd deleted file mode 100644 index ecf9efd..0000000 Binary files a/api/batch_api.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/batch_api_cs.cp312-win_amd64.pyd b/api/batch_api_cs.cp312-win_amd64.pyd deleted file mode 100644 index 91ce87b..0000000 Binary files a/api/batch_api_cs.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/batch_exe.cp312-win_amd64.pyd b/api/batch_exe.cp312-win_amd64.pyd deleted file mode 100644 index c461c6b..0000000 Binary files a/api/batch_exe.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/clean_api.cp312-win_amd64.pyd b/api/clean_api.cp312-win_amd64.pyd deleted file mode 100644 index fe4aec3..0000000 Binary files a/api/clean_api.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/connection.cp312-win_amd64.pyd b/api/connection.cp312-win_amd64.pyd deleted file mode 100644 index f73a701..0000000 Binary files a/api/connection.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/database.cp312-win_amd64.pyd b/api/database.cp312-win_amd64.pyd deleted file mode 100644 index eba53cc..0000000 Binary files a/api/database.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/extension_data.cp312-win_amd64.pyd b/api/extension_data.cp312-win_amd64.pyd deleted file mode 100644 index e291367..0000000 Binary files a/api/extension_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/inp_in.cp312-win_amd64.pyd b/api/inp_in.cp312-win_amd64.pyd deleted file mode 100644 index d255630..0000000 Binary files a/api/inp_in.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/inp_out.cp312-win_amd64.pyd b/api/inp_out.cp312-win_amd64.pyd deleted file mode 100644 index 36da061..0000000 Binary files a/api/inp_out.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/postgresql_info.cp312-win_amd64.pyd b/api/postgresql_info.cp312-win_amd64.pyd deleted file mode 100644 index ba6fb23..0000000 Binary files a/api/postgresql_info.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/project.cp312-win_amd64.pyd b/api/project.cp312-win_amd64.pyd deleted file mode 100644 index e79f3f0..0000000 Binary files a/api/project.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s0_base.cp312-win_amd64.pyd b/api/s0_base.cp312-win_amd64.pyd deleted file mode 100644 index 8088274..0000000 Binary files a/api/s0_base.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s10_status.cp312-win_amd64.pyd b/api/s10_status.cp312-win_amd64.pyd deleted file mode 100644 index 985db5a..0000000 Binary files a/api/s10_status.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s11_patterns.cp312-win_amd64.pyd b/api/s11_patterns.cp312-win_amd64.pyd deleted file mode 100644 index 3639912..0000000 Binary files a/api/s11_patterns.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s12_curves.cp312-win_amd64.pyd b/api/s12_curves.cp312-win_amd64.pyd deleted file mode 100644 index 9b40b9e..0000000 Binary files a/api/s12_curves.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s13_controls.cp312-win_amd64.pyd b/api/s13_controls.cp312-win_amd64.pyd deleted file mode 100644 index 96683dc..0000000 Binary files a/api/s13_controls.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s14_rules.cp312-win_amd64.pyd b/api/s14_rules.cp312-win_amd64.pyd deleted file mode 100644 index 0a743fd..0000000 Binary files a/api/s14_rules.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s15_energy.cp312-win_amd64.pyd b/api/s15_energy.cp312-win_amd64.pyd deleted file mode 100644 index eaed97d..0000000 Binary files a/api/s15_energy.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s16_emitters.cp312-win_amd64.pyd b/api/s16_emitters.cp312-win_amd64.pyd deleted file mode 100644 index 82ed3a0..0000000 Binary files a/api/s16_emitters.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s17_quality.cp312-win_amd64.pyd b/api/s17_quality.cp312-win_amd64.pyd deleted file mode 100644 index 4b2e3a2..0000000 Binary files a/api/s17_quality.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s18_sources.cp312-win_amd64.pyd b/api/s18_sources.cp312-win_amd64.pyd deleted file mode 100644 index eee5084..0000000 Binary files a/api/s18_sources.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s19_reactions.cp312-win_amd64.pyd b/api/s19_reactions.cp312-win_amd64.pyd deleted file mode 100644 index b397cd3..0000000 Binary files a/api/s19_reactions.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s1_title.cp312-win_amd64.pyd b/api/s1_title.cp312-win_amd64.pyd deleted file mode 100644 index 3d4a00e..0000000 Binary files a/api/s1_title.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s20_mixing.cp312-win_amd64.pyd b/api/s20_mixing.cp312-win_amd64.pyd deleted file mode 100644 index c704347..0000000 Binary files a/api/s20_mixing.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s21_times.cp312-win_amd64.pyd b/api/s21_times.cp312-win_amd64.pyd deleted file mode 100644 index f35a309..0000000 Binary files a/api/s21_times.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s22_report.cp312-win_amd64.pyd b/api/s22_report.cp312-win_amd64.pyd deleted file mode 100644 index 749f0d4..0000000 Binary files a/api/s22_report.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s23_options.cp312-win_amd64.pyd b/api/s23_options.cp312-win_amd64.pyd deleted file mode 100644 index 7d5b008..0000000 Binary files a/api/s23_options.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s23_options_util.cp312-win_amd64.pyd b/api/s23_options_util.cp312-win_amd64.pyd deleted file mode 100644 index eda920f..0000000 Binary files a/api/s23_options_util.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s23_options_v3.cp312-win_amd64.pyd b/api/s23_options_v3.cp312-win_amd64.pyd deleted file mode 100644 index ef15725..0000000 Binary files a/api/s23_options_v3.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s24_coordinates.cp312-win_amd64.pyd b/api/s24_coordinates.cp312-win_amd64.pyd deleted file mode 100644 index 09185a8..0000000 Binary files a/api/s24_coordinates.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s25_vertices.cp312-win_amd64.pyd b/api/s25_vertices.cp312-win_amd64.pyd deleted file mode 100644 index c60ca60..0000000 Binary files a/api/s25_vertices.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s26_labels.cp312-win_amd64.pyd b/api/s26_labels.cp312-win_amd64.pyd deleted file mode 100644 index 8dd887a..0000000 Binary files a/api/s26_labels.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s27_backdrop.cp312-win_amd64.pyd b/api/s27_backdrop.cp312-win_amd64.pyd deleted file mode 100644 index c0a38f2..0000000 Binary files a/api/s27_backdrop.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s28_end.cp312-win_amd64.pyd b/api/s28_end.cp312-win_amd64.pyd deleted file mode 100644 index 832d245..0000000 Binary files a/api/s28_end.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s29_scada_device.cp312-win_amd64.pyd b/api/s29_scada_device.cp312-win_amd64.pyd deleted file mode 100644 index 55e00a2..0000000 Binary files a/api/s29_scada_device.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s2_junctions.cp312-win_amd64.pyd b/api/s2_junctions.cp312-win_amd64.pyd deleted file mode 100644 index fd5f059..0000000 Binary files a/api/s2_junctions.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s30_scada_device_data.cp312-win_amd64.pyd b/api/s30_scada_device_data.cp312-win_amd64.pyd deleted file mode 100644 index c6285e7..0000000 Binary files a/api/s30_scada_device_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s31_scada_element.cp312-win_amd64.pyd b/api/s31_scada_element.cp312-win_amd64.pyd deleted file mode 100644 index ad4e195..0000000 Binary files a/api/s31_scada_element.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s32_region.cp312-win_amd64.pyd b/api/s32_region.cp312-win_amd64.pyd deleted file mode 100644 index 149da1c..0000000 Binary files a/api/s32_region.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s32_region_util.cp312-win_amd64.pyd b/api/s32_region_util.cp312-win_amd64.pyd deleted file mode 100644 index 43d7f93..0000000 Binary files a/api/s32_region_util.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s33_dma.cp312-win_amd64.pyd b/api/s33_dma.cp312-win_amd64.pyd deleted file mode 100644 index 36c5277..0000000 Binary files a/api/s33_dma.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s33_dma_cal.cp312-win_amd64.pyd b/api/s33_dma_cal.cp312-win_amd64.pyd deleted file mode 100644 index 2d8d8f0..0000000 Binary files a/api/s33_dma_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s33_dma_gen.cp312-win_amd64.pyd b/api/s33_dma_gen.cp312-win_amd64.pyd deleted file mode 100644 index 02ee7cd..0000000 Binary files a/api/s33_dma_gen.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s34_sa.cp312-win_amd64.pyd b/api/s34_sa.cp312-win_amd64.pyd deleted file mode 100644 index 7643dba..0000000 Binary files a/api/s34_sa.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s34_sa_cal.cp312-win_amd64.pyd b/api/s34_sa_cal.cp312-win_amd64.pyd deleted file mode 100644 index 3f7990f..0000000 Binary files a/api/s34_sa_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s34_sa_gen.cp312-win_amd64.pyd b/api/s34_sa_gen.cp312-win_amd64.pyd deleted file mode 100644 index 78cc5b5..0000000 Binary files a/api/s34_sa_gen.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s35_vd.cp312-win_amd64.pyd b/api/s35_vd.cp312-win_amd64.pyd deleted file mode 100644 index 866043d..0000000 Binary files a/api/s35_vd.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s35_vd_cal.cp312-win_amd64.pyd b/api/s35_vd_cal.cp312-win_amd64.pyd deleted file mode 100644 index 2c67afc..0000000 Binary files a/api/s35_vd_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s35_vd_gen.cp312-win_amd64.pyd b/api/s35_vd_gen.cp312-win_amd64.pyd deleted file mode 100644 index 462d90d..0000000 Binary files a/api/s35_vd_gen.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s36_wda.cp312-win_amd64.pyd b/api/s36_wda.cp312-win_amd64.pyd deleted file mode 100644 index 5f4ffea..0000000 Binary files a/api/s36_wda.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s36_wda_cal.cp312-win_amd64.pyd b/api/s36_wda_cal.cp312-win_amd64.pyd deleted file mode 100644 index 3654752..0000000 Binary files a/api/s36_wda_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s38_scada_info.cp312-win_amd64.pyd b/api/s38_scada_info.cp312-win_amd64.pyd deleted file mode 100644 index 9820e83..0000000 Binary files a/api/s38_scada_info.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s39_user.cp312-win_amd64.pyd b/api/s39_user.cp312-win_amd64.pyd deleted file mode 100644 index 6a5cbda..0000000 Binary files a/api/s39_user.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s3_reservoirs.cp312-win_amd64.pyd b/api/s3_reservoirs.cp312-win_amd64.pyd deleted file mode 100644 index 0e12595..0000000 Binary files a/api/s3_reservoirs.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s40_schema.cp312-win_amd64.pyd b/api/s40_schema.cp312-win_amd64.pyd deleted file mode 100644 index ae02084..0000000 Binary files a/api/s40_schema.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s41_pipe_risk_probability.cp312-win_amd64.pyd b/api/s41_pipe_risk_probability.cp312-win_amd64.pyd deleted file mode 100644 index 875bd22..0000000 Binary files a/api/s41_pipe_risk_probability.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s42_sensor_placement.cp312-win_amd64.pyd b/api/s42_sensor_placement.cp312-win_amd64.pyd deleted file mode 100644 index 0967316..0000000 Binary files a/api/s42_sensor_placement.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s43_burst_locate_result.cp312-win_amd64.pyd b/api/s43_burst_locate_result.cp312-win_amd64.pyd deleted file mode 100644 index 6c00afc..0000000 Binary files a/api/s43_burst_locate_result.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s4_tanks.cp312-win_amd64.pyd b/api/s4_tanks.cp312-win_amd64.pyd deleted file mode 100644 index 408e143..0000000 Binary files a/api/s4_tanks.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s5_pipes.cp312-win_amd64.pyd b/api/s5_pipes.cp312-win_amd64.pyd deleted file mode 100644 index 118edab..0000000 Binary files a/api/s5_pipes.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s6_pumps.cp312-win_amd64.pyd b/api/s6_pumps.cp312-win_amd64.pyd deleted file mode 100644 index 9edb364..0000000 Binary files a/api/s6_pumps.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s7_valves.cp312-win_amd64.pyd b/api/s7_valves.cp312-win_amd64.pyd deleted file mode 100644 index bfab677..0000000 Binary files a/api/s7_valves.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s8_tags.cp312-win_amd64.pyd b/api/s8_tags.cp312-win_amd64.pyd deleted file mode 100644 index 0cfdfb6..0000000 Binary files a/api/s8_tags.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/s9_demands.cp312-win_amd64.pyd b/api/s9_demands.cp312-win_amd64.pyd deleted file mode 100644 index f7d4a18..0000000 Binary files a/api/s9_demands.cp312-win_amd64.pyd and /dev/null differ diff --git a/api/sections.cp312-win_amd64.pyd b/api/sections.cp312-win_amd64.pyd deleted file mode 100644 index 80cda48..0000000 Binary files a/api/sections.cp312-win_amd64.pyd and /dev/null differ diff --git a/api_ex/kmeans_sensor.cp312-win_amd64.pyd b/api_ex/kmeans_sensor.cp312-win_amd64.pyd deleted file mode 100644 index 82c1316..0000000 Binary files a/api_ex/kmeans_sensor.cp312-win_amd64.pyd and /dev/null differ diff --git a/api_ex/remove_sb_columns.py b/api_ex/remove_sb_columns.py deleted file mode 100644 index 93f3f70..0000000 --- a/api_ex/remove_sb_columns.py +++ /dev/null @@ -1,32 +0,0 @@ -import csv -from pathlib import Path - -# infile = Path(r"c:\copilot codes\dataclean\Flow_Timedata2025_new_format.csv") -# outfile = Path(r"c:\copilot codes\dataclean\szh_flow_scada.csv") - -infile = Path(r"c:\copilot codes\dataclean\Pressure_Timedata2025_new_format.csv") -outfile = Path(r"c:\copilot codes\dataclean\szh_pressure_scada.csv") - -with infile.open("r", newline="", encoding="utf-8") as f_in: - reader = csv.reader(f_in) - rows = list(reader) - -if not rows: - print("input file is empty") - raise SystemExit(1) - -headers = rows[0] -# keep columns whose header does NOT contain 'SB_' -keep_indices = [i for i,h in enumerate(headers) if 'SB_' not in h] -removed = [h for i,h in enumerate(headers) if 'SB_' in h] - -with outfile.open("w", newline="", encoding="utf-8") as f_out: - writer = csv.writer(f_out) - for row in rows: - # ensure row has same length as headers - if len(row) < len(headers): - row = row + [''] * (len(headers) - len(row)) - newrow = [row[i] for i in keep_indices] - writer.writerow(newrow) - -print(f"Wrote {outfile} — removed {len(removed)} columns containing 'SB_'.") diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/algorithms/__init__.py b/app/algorithms/__init__.py new file mode 100644 index 0000000..57dc324 --- /dev/null +++ b/app/algorithms/__init__.py @@ -0,0 +1,36 @@ +from app.algorithms.cleaning import flow_data_clean, pressure_data_clean +from app.algorithms.sensor import ( + pressure_sensor_placement_sensitivity, + pressure_sensor_placement_kmeans, +) +from app.algorithms.isolation.valve import valve_isolation_analysis +from app.algorithms.leakage import LeakageIdentifier +from app.algorithms.health import PipelineHealthAnalyzer +from app.algorithms.burst_location import run_burst_location +from app.algorithms.simulation.scenarios import ( + convert_to_local_unit, + burst_analysis, + valve_close_analysis, + flushing_analysis, + contaminant_simulation, + age_analysis, + pressure_regulation, +) + +__all__ = [ + "flow_data_clean", + "pressure_data_clean", + "pressure_sensor_placement_sensitivity", + "pressure_sensor_placement_kmeans", + "convert_to_local_unit", + "burst_analysis", + "valve_close_analysis", + "flushing_analysis", + "contaminant_simulation", + "age_analysis", + "pressure_regulation", + "valve_isolation_analysis", + "LeakageIdentifier", + "PipelineHealthAnalyzer", + "run_burst_location", +] diff --git a/app/algorithms/_utils.py b/app/algorithms/_utils.py new file mode 100644 index 0000000..5137943 --- /dev/null +++ b/app/algorithms/_utils.py @@ -0,0 +1,88 @@ +import os + +import pandas as pd + + +def fill_time_gaps( + data: pd.DataFrame, + time_col: str = "time", + freq: str = "1min", + short_gap_threshold: int = 10, +) -> pd.DataFrame: + """ + 补齐缺失时间戳并填补数据缺口。 + + Args: + data: 包含时间列的 DataFrame + time_col: 时间列名(默认 'time') + freq: 重采样频率(默认 '1min') + short_gap_threshold: 短缺口阈值(分钟),<=此值用线性插值,>此值用前向填充 + + Returns: + 补齐时间后的 DataFrame(保留原时间列格式) + """ + if time_col not in data.columns: + raise ValueError(f"时间列 '{time_col}' 不存在于数据中") + + # 解析时间列并设为索引 + data = data.copy() + data[time_col] = pd.to_datetime(data[time_col], utc=True) + data_indexed = data.set_index(time_col) + + # 生成完整时间范围 + full_range = pd.date_range( + start=data_indexed.index.min(), end=data_indexed.index.max(), freq=freq + ) + + # 重索引以补齐缺失时间点,同时保留原始时间戳 + combined_index = data_indexed.index.union(full_range).sort_values().unique() + data_reindexed = data_indexed.reindex(combined_index) + + # 按列处理缺口 + for col in data_reindexed.columns: + # 识别缺失值位置 + is_missing = data_reindexed[col].isna() + + # 计算连续缺失的长度 + missing_groups = (is_missing != is_missing.shift()).cumsum() + gap_lengths = is_missing.groupby(missing_groups).transform("sum") + + # 短缺口:时间插值 + short_gap_mask = is_missing & (gap_lengths <= short_gap_threshold) + if short_gap_mask.any(): + data_reindexed.loc[short_gap_mask, col] = ( + data_reindexed[col] + .interpolate(method="time", limit_area="inside") + .loc[short_gap_mask] + ) + + # 长缺口:前向填充 + long_gap_mask = is_missing & (gap_lengths > short_gap_threshold) + if long_gap_mask.any(): + data_reindexed.loc[long_gap_mask, col] = ( + data_reindexed[col].ffill().loc[long_gap_mask] + ) + + # 重置索引并恢复时间列(保留原格式) + data_result = data_reindexed.reset_index() + data_result.rename(columns={"index": time_col}, inplace=True) + + # 保留时区信息 + data_result[time_col] = data_result[time_col].dt.strftime("%Y-%m-%dT%H:%M:%S%z") + # 修正时区格式(Python的%z输出为+0000,需转为+00:00) + data_result[time_col] = data_result[time_col].str.replace( + r"(\+\d{2})(\d{2})$", r"\1:\2", regex=True + ) + + return data_result + + +def _cleanup_temp_files(prefix: str) -> None: + """清理 EPANET 仿真产生的临时文件。""" + for ext in [".inp", ".rpt", ".bin", ".out"]: + temp_file = prefix + ext + if os.path.exists(temp_file): + try: + os.remove(temp_file) + except OSError: + pass diff --git a/app/algorithms/burst_detection/__init__.py b/app/algorithms/burst_detection/__init__.py new file mode 100644 index 0000000..226dc73 --- /dev/null +++ b/app/algorithms/burst_detection/__init__.py @@ -0,0 +1,3 @@ +from app.algorithms.burst_detection.burst_detector import BurstDetector + +__all__ = ["BurstDetector"] diff --git a/app/algorithms/burst_detection/burst_detector.py b/app/algorithms/burst_detection/burst_detector.py new file mode 100644 index 0000000..530ae6b --- /dev/null +++ b/app/algorithms/burst_detection/burst_detector.py @@ -0,0 +1,259 @@ +from __future__ import annotations + +from typing import Any + +import numpy as np +import pandas as pd +from scipy.fft import fft, ifft +from sklearn.ensemble import IsolationForest + +PressureDataInput = ( + pd.DataFrame + | dict[str, list[Any]] + | list[dict[str, Any]] + | list[list[Any]] + | np.ndarray +) +IGNORED_OBSERVATION_COLUMNS = {"time", "timestamp", "datetime", "date"} + + +class BurstDetector: + """FFT + IsolationForest based burst detection for daily aligned pressure data.""" + + def __init__( + self, + *, + mu: int = 100, + points_per_day: int = 1440, + iforest_params: dict[str, Any] | None = None, + ) -> None: + if points_per_day <= 0: + raise ValueError("points_per_day 必须大于 0。") + if mu <= 0: + raise ValueError("mu 必须大于 0。") + + self.mu = int(mu) + self.points_per_day = int(points_per_day) + self.iforest_params = { + "n_estimators": 50, + "random_state": 42, + "contamination": "auto", + } + if iforest_params: + self.iforest_params.update(iforest_params) + + self.data: np.ndarray | None = None + self.sensor_names: list[str] = [] + self.high_freq_features: np.ndarray | None = None + + def load_data( + self, + data_source: PressureDataInput, + *, + sensor_nodes: list[str] | None = None, + ) -> pd.DataFrame: + """ + 标准化输入观测数据为 DataFrame。 + + 支持的 `data_source` 格式: + - `pd.DataFrame` + 每一列代表一个传感器,每一行代表一个时间点。 + - `dict[str, list[Any]]` + 键为传感器 ID,值为该传感器按时间顺序排列的压力序列。 + 例如:`{"J1": [101.2, 101.0], "J2": [99.8, 99.7]}`。 + - `list[dict[str, Any]]` + 每个字典代表一个时间点,键为传感器 ID,值为该时刻压力。 + 例如:`[{"J1": 101.2, "J2": 99.8}, {"J1": 101.0, "J2": 99.7}]`。 + - `list[list[Any]]` + 二维列表,格式为 `(时间点数, 传感器数)`。 + 例如:`[[101.2, 99.8], [101.0, 99.7]]`。 + - `np.ndarray` + 二维数组,形状必须为 `(时间点数, 传感器数)`。 + + 参数: + - `sensor_nodes`: + 可选的传感器列筛选列表。传入后,数据中必须包含这些列名。 + + 返回: + - 标准化后的 `pd.DataFrame`,列为传感器,行为时间点。 + """ + if isinstance(data_source, np.ndarray): + observation_df = pd.DataFrame(data_source) + elif isinstance(data_source, pd.DataFrame): + observation_df = data_source.copy() + else: + observation_df = pd.DataFrame(data_source) + + return self._normalize_observation_frame( + observation_df=observation_df, sensor_nodes=sensor_nodes + ) + + def process( + self, + observed_pressure_data: PressureDataInput, + *, + sensor_nodes: list[str] | None = None, + ) -> np.ndarray: + """ + 对输入压力序列按天切片,并提取每天末时刻的高频特征。 + + `observed_pressure_data` 的格式与 `load_data()` 一致,统一要求: + - 数据必须表示为“行=时间点、列=传感器”。 + - 总行数必须是 `points_per_day` 的整数倍。 + - 至少需要 2 天数据,即总行数 `>= 2 * points_per_day`。 + + 例如: + - 当 `points_per_day=1440` 时,15 天数据的形状通常为 `(21600, 传感器数)`。 + - 若传入 `sensor_nodes=["J1", "J2"]`,则输入中必须存在 `J1/J2` 两列。 + + 返回: + - `np.ndarray`,形状为 `(天数, 传感器数)`, + 每个值表示对应传感器在当天末时刻提取出的高频分量。 + """ + observation_df = self.load_data( + observed_pressure_data, + sensor_nodes=sensor_nodes, + ) + matrix = observation_df.to_numpy(dtype=float) + total_points, sensor_count = matrix.shape + if sensor_count == 0: + raise ValueError("压力观测数据中未找到可用传感器列。") + if total_points < self.points_per_day * 2: + raise ValueError("至少需要 2 天的观测数据才能执行爆管侦测。") + if total_points % self.points_per_day != 0: + raise ValueError("观测数据长度必须能被每日采样点数整除,以便按天切分。") + + day_count = total_points // self.points_per_day + high_freq_features = np.zeros((day_count, sensor_count), dtype=float) + + for sensor_idx in range(sensor_count): + sensor_series = matrix[:, sensor_idx] + for day_idx in range(day_count): + start = day_idx * self.points_per_day + end = (day_idx + 1) * self.points_per_day + day_data = sensor_series[start:end] + mirrored_data = np.concatenate([day_data, day_data[::-1]]) + transformed = fft(mirrored_data) + transformed[self.mu : len(mirrored_data) - self.mu + 1] = 0 + low_freq = ifft(transformed).real + high_freq = day_data - low_freq[: self.points_per_day] + high_freq_features[day_idx, sensor_idx] = float(high_freq[-1]) + + self.data = matrix + self.sensor_names = [str(column) for column in observation_df.columns] + self.high_freq_features = high_freq_features + return high_freq_features + + def detect(self) -> pd.DataFrame: + if self.high_freq_features is None: + raise ValueError("特征未提取。请先调用 process()。") + + day_count = self.high_freq_features.shape[0] + if day_count < 2: + raise ValueError("孤立森林至少需要 2 天特征数据。") + + clf = IsolationForest( + n_estimators=self.iforest_params.get("n_estimators", 50), + max_samples=day_count, + random_state=self.iforest_params.get("random_state", 42), + contamination=self.iforest_params.get("contamination", "auto"), + **{ + key: value + for key, value in self.iforest_params.items() + if key not in {"n_estimators", "random_state", "contamination"} + }, + ) + clf.fit(self.high_freq_features) + + scores = clf.decision_function(self.high_freq_features) + predictions = clf.predict(self.high_freq_features) + result_df = pd.DataFrame( + { + "Day": range(1, day_count + 1), + "Score": scores.astype(float), + "Prediction": predictions.astype(int), + } + ) + result_df["IsBurst"] = result_df["Prediction"].eq(-1) + result_df.attrs["sensor_nodes"] = self.sensor_names.copy() + result_df.attrs["high_freq_features"] = self.high_freq_features.copy() + result_df.attrs["day_count"] = day_count + result_df.attrs["points_per_day"] = self.points_per_day + result_df.attrs["sample_count"] = ( + int(self.data.shape[0]) if self.data is not None else 0 + ) + return result_df + + def run_detection( + self, + observed_pressure_data: PressureDataInput, + *, + sensor_nodes: list[str] | None = None, + ) -> pd.DataFrame: + """ + 执行完整爆管侦测流程。 + + 输入格式与 `process()` 相同: + - `DataFrame` / `dict[str, list[Any]]` / `list[dict[str, Any]]` / `list[list[Any]]` / `np.ndarray` + - 行表示时间点,列表示传感器 + - 总行数必须能被 `points_per_day` 整除 + + 返回结果包含列: + - `Day`: 第几天(从 1 开始) + - `Score`: IsolationForest 异常分数,越小越异常 + - `Prediction`: `-1` 表示异常,`1` 表示正常 + - `IsBurst`: 是否判定为异常日 + """ + self.process(observed_pressure_data, sensor_nodes=sensor_nodes) + return self.detect() + + @staticmethod + def _normalize_observation_frame( + *, + observation_df: pd.DataFrame, + sensor_nodes: list[str] | None, + ) -> pd.DataFrame: + if observation_df.empty: + raise ValueError("压力观测数据为空。") + + normalized_df = observation_df.copy() + normalized_df.columns = [str(column) for column in normalized_df.columns] + normalized_df = normalized_df.drop( + columns=[ + column + for column in normalized_df.columns + if column.lower() in IGNORED_OBSERVATION_COLUMNS + or column.lower().startswith("unnamed:") + ], + errors="ignore", + ) + + if sensor_nodes: + selected_columns = [str(node) for node in sensor_nodes] + missing_columns = [ + column + for column in selected_columns + if column not in normalized_df.columns + ] + if missing_columns: + preview = ", ".join(missing_columns[:10]) + raise ValueError(f"观测数据缺少传感器列: {preview}") + normalized_df = normalized_df.loc[:, selected_columns] + else: + candidate_df = normalized_df.apply(pd.to_numeric, errors="coerce") + normalized_df = candidate_df.loc[:, candidate_df.notna().any(axis=0)] + + if normalized_df.empty: + raise ValueError("未识别到可用的数值型压力观测列。") + + normalized_df = normalized_df.apply(pd.to_numeric, errors="coerce") + invalid_columns = [ + column + for column in normalized_df.columns + if normalized_df[column].isna().any() + ] + if invalid_columns: + preview = ", ".join(invalid_columns[:10]) + raise ValueError(f"压力观测数据包含非数值或缺失值: {preview}") + + return normalized_df.reset_index(drop=True) diff --git a/app/algorithms/burst_location/__init__.py b/app/algorithms/burst_location/__init__.py new file mode 100644 index 0000000..c7ec7a1 --- /dev/null +++ b/app/algorithms/burst_location/__init__.py @@ -0,0 +1,3 @@ +from .burst_location import run_burst_location + +__all__ = ["run_burst_location"] diff --git a/app/algorithms/burst_location/burst_location.py b/app/algorithms/burst_location/burst_location.py new file mode 100644 index 0000000..4f4f971 --- /dev/null +++ b/app/algorithms/burst_location/burst_location.py @@ -0,0 +1,342 @@ +import argparse +import json +import logging +from multiprocessing import cpu_count +from pathlib import Path +from typing import Any, Iterable + +import pandas as pd + +from app.algorithms.burst_location import leak_simulator + +from .burst_locator import ( + DN_search_multi_simple_add_flow_count_new, +) +from .network_model import ( + _build_node_pipe_maps, + cal_node_coordinate, + construct_graph, + load_inp, + read_inf_inp, + read_inf_inp_other, +) + +DEFAULT_N_WORKERS = max(1, min(cpu_count() - 1, 4)) +# DEFAULT_N_WORKERS = max(1, cpu_count() - 1) +logger = logging.getLogger(__name__) + + +def _read_id_list_json(path): + if path is None: + return None + data = json.loads(Path(path).read_text(encoding="utf-8")) + if isinstance(data, list): + return [str(item) for item in data] + if isinstance(data, dict): + if "ids" in data and isinstance(data["ids"], list): + return [str(item) for item in data["ids"]] + raise ValueError(f"ID JSON must be list or dict with key 'ids': {path}") + raise ValueError(f"Unsupported ID JSON format: {path}") + + +def _read_series_csv(path): + if path is None: + return None + df = pd.read_csv(path) + if df.shape[1] < 2: + raise ValueError(f"CSV must contain at least two columns (id,value): {path}") + if {"id", "value"}.issubset(df.columns): + id_col, value_col = "id", "value" + else: + id_col, value_col = df.columns[0], df.columns[1] + series = pd.Series( + df[value_col].values, index=df[id_col].astype(str).values, dtype=float + ) + return series + + +def _align_scada_series( + series: pd.Series, ids: Iterable[str], series_name: str +) -> pd.Series: + ids = [str(item) for item in ids] + aligned = series.copy() + aligned.index = aligned.index.map(str) + missing_ids = [item for item in ids if item not in aligned.index] + if missing_ids: + preview = ", ".join(missing_ids[:10]) + raise ValueError(f"{series_name} missing IDs: {preview}") + aligned = pd.to_numeric(aligned.loc[ids], errors="coerce") + invalid_ids = aligned[aligned.isna()].index.tolist() + if invalid_ids: + preview = ", ".join(invalid_ids[:10]) + raise ValueError( + f"{series_name} contains non-numeric values for IDs: {preview}" + ) + return aligned + + +def _validate_flow_inputs( + flow_scada_ids: list[str] | None, + burst_flow: pd.Series | None, + normal_flow: pd.Series | None, +) -> tuple[bool, list[str]]: + has_any_flow = any( + value is not None for value in [flow_scada_ids, burst_flow, normal_flow] + ) + has_all_flow = all( + value is not None for value in [flow_scada_ids, burst_flow, normal_flow] + ) + if has_any_flow and not has_all_flow: + raise ValueError( + "flow_scada_ids, burst_flow, and normal_flow must be provided together." + ) + + if not has_all_flow: + return False, [] + + flow_ids = [str(item) for item in (flow_scada_ids or [])] + if len(flow_ids) == 0: + raise ValueError("flow_scada_ids cannot be empty when flow data is provided.") + return True, flow_ids + + +def _build_top_candidates(similarity_series: pd.Series) -> list[dict[str, Any]]: + top_series = similarity_series.iloc[:10] + return [ + {"pipe_id": str(pipe_id), "similarity": float(score)} + for pipe_id, score in top_series.items() + ] + + +def run_burst_location( + wn_inp_path: str, + pressure_scada_ids: list[str], + burst_pressure: pd.Series, + normal_pressure: pd.Series, + burst_leakage: float, + flow_scada_ids: list[str] | None = None, + burst_flow: pd.Series | None = None, + normal_flow: pd.Series | None = None, + min_dpressure: float = 2.0, + basic_pressure: float = 10.0, + n_workers: int = DEFAULT_N_WORKERS, + partition_on_full_graph: bool = True, + visualize_partition: bool = True, + visualize_pause_seconds: float = 0.3, + final_candidates_csv_path: ( + str | None + ) = "temp/burst_location/final_round_candidates.csv", +) -> dict[str, Any]: + if pressure_scada_ids is None or len(pressure_scada_ids) == 0: + raise ValueError("pressure_scada_ids cannot be empty.") + if burst_pressure is None or normal_pressure is None: + raise ValueError("burst_pressure and normal_pressure are required.") + + has_all_flow, flow_ids = _validate_flow_inputs( + flow_scada_ids=flow_scada_ids, + burst_flow=burst_flow, + normal_flow=normal_flow, + ) + + inp_path = Path(wn_inp_path) + wn = load_inp( + inp_name=inp_path.name, + inp_location=str(inp_path.parent) + "/", + inp_time=0, + driven_mode="PDD", + require_p=float(basic_pressure), + minimum_p=0.0, + ) + + ( + all_node, + _, + node_coordinates, + all_pipe, + _, + _, + pipe_length, + pipe_diameter, + ) = read_inf_inp(wn) + + candidate_pipe, _ = leak_simulator.cal_possible_pipe( + burst_leakage, all_pipe, pipe_diameter + ) + + _, pipe_start_node_all, pipe_end_node_all = read_inf_inp_other(wn) + node_x, node_y = cal_node_coordinate(all_node, node_coordinates) + G0 = construct_graph(wn) + node_pipe_dic, couple_node_length = _build_node_pipe_maps( + all_node, + all_pipe, + pipe_start_node_all, + pipe_end_node_all, + pipe_length, + ) + all_node_series = pd.Series(range(len(all_node)), index=all_node) + + pressure_ids = [str(item) for item in pressure_scada_ids] + normal_pressure_aligned = _align_scada_series( + normal_pressure, pressure_ids, "normal_pressure" + ) + burst_pressure_aligned = _align_scada_series( + burst_pressure, pressure_ids, "burst_pressure" + ) + pressure_normal = normal_pressure_aligned.to_frame().T + pressure_monitor = burst_pressure_aligned.to_frame().T + pressure_predict = pressure_normal.copy() + timestep_list = list(pressure_normal.index) + + if has_all_flow: + normal_flow_aligned = _align_scada_series(normal_flow, flow_ids, "normal_flow") + burst_flow_aligned = _align_scada_series(burst_flow, flow_ids, "burst_flow") + flow_normal = normal_flow_aligned.to_frame().T + flow_monitor = burst_flow_aligned.to_frame().T + flow_predict = flow_normal.copy() + similarity_mode = "CDF" + max_flow = flow_normal.iloc[0, :].abs() + else: + flow_normal = pd.DataFrame(index=timestep_list) + flow_monitor = pd.DataFrame(index=timestep_list) + flow_predict = pd.DataFrame(index=timestep_list) + similarity_mode = "CAD_new_gy" + max_flow = pd.Series(dtype=float) + + stage_timing: dict[str, Any] = {} + try: + ( + located_pipe, + elapsed_seconds, + simulation_times, + _, + similarity_series, + exit_condition, + final_candidates_csv, + ) = DN_search_multi_simple_add_flow_count_new( + wn=wn, + wn_inp_path=str(inp_path), + G0=G0, + all_node=all_node, + node_x=node_x, + node_y=node_y, + pipe_start_node_all=pipe_start_node_all, + pipe_end_node_all=pipe_end_node_all, + pipe_diameter=pipe_diameter, + couple_node_length=couple_node_length, + node_pipe_dic=node_pipe_dic, + all_node_series=all_node_series, + top_group_ratio=0.3, + top_pipe_num_max=80, + top_pipe_num_min=10, + candidate_pipe_input_initial=candidate_pipe, + similarity_mode=similarity_mode, + pressure_monitor=pressure_monitor, + pressure_predict=pressure_predict, + pressure_normal=pressure_normal, + pressure_leak_all=None, + flow_monitor=flow_monitor, + flow_predict=flow_predict, + flow_normal=flow_normal, + flow_leak_all=None, + timestep_list=timestep_list, + max_flow=max_flow, + group_basic_num=30, + Top_sensor_num=min(5, len(pressure_ids)), + if_gy=0, + pressure_threshold=float(min_dpressure), + leak_mag=float(burst_leakage), + n_workers=max(1, int(n_workers)), + stage_timing=stage_timing, + partition_on_full_graph=partition_on_full_graph, + visualize_partition=visualize_partition, + visualize_pause_seconds=visualize_pause_seconds, + final_candidates_csv_path=final_candidates_csv_path, + ) + except Exception as exc: + logger.exception("Burst location algorithm execution failed.") + raise RuntimeError(f"Failed to run burst location algorithm: {exc}") from exc + + return { + "located_pipe": located_pipe, + "burst_leakage": float(burst_leakage), + "elapsed_seconds": elapsed_seconds, + "simulation_times": int(simulation_times), + "top_candidates": _build_top_candidates(similarity_series), + "similarity_mode": similarity_mode, + "exit_condition": exit_condition, + "final_candidates_csv": final_candidates_csv, + "stage_timing_seconds": stage_timing, + } + + +def _parse_args(): + parser = argparse.ArgumentParser(description="爆管定位主函数入口") + parser.add_argument("--wn-inp", required=True, help="EPANET inp 文件路径") + parser.add_argument( + "--pressure-ids-json", required=True, help="压力SCADA ID列表 JSON 文件" + ) + parser.add_argument( + "--flow-ids-json", default=None, help="(可选)流量SCADA ID列表 JSON 文件" + ) + parser.add_argument( + "--burst-pressure-csv", required=True, help="爆管时压力 CSV(id,value)" + ) + parser.add_argument( + "--normal-pressure-csv", required=True, help="正常时压力 CSV(id,value)" + ) + parser.add_argument( + "--burst-flow-csv", default=None, help="(可选)爆管时流量 CSV(id,value)" + ) + parser.add_argument( + "--normal-flow-csv", default=None, help="(可选)正常时流量 CSV(id,value)" + ) + parser.add_argument( + "--burst-leakage", type=float, required=True, help="爆管漏损流量" + ) + parser.add_argument( + "--min-dpressure", + type=float, + default=2.0, + help="(可选)最小压降阈值,默认 2.0", + ) + parser.add_argument( + "--basic-pressure", + type=float, + default=10.0, + help="(可选)基础服务压力,默认 10.0", + ) + parser.add_argument( + "--n-workers", + type=int, + default=DEFAULT_N_WORKERS, + help="(可选)特征中心模拟进程数,默认 max(1, min(cpu_count()-1, 4))", + ) + parser.add_argument( + "--final-candidates-csv-path", + default="temp/burst_location/final_round_candidates.csv", + help="(可选)最后一轮候选管道明细 CSV 输出路径", + ) + return parser.parse_args() + + +def main(): + args = _parse_args() + result = run_burst_location( + wn_inp_path=args.wn_inp, + pressure_scada_ids=_read_id_list_json(args.pressure_ids_json), + burst_pressure=_read_series_csv(args.burst_pressure_csv), + normal_pressure=_read_series_csv(args.normal_pressure_csv), + burst_leakage=args.burst_leakage, + flow_scada_ids=_read_id_list_json(args.flow_ids_json), + burst_flow=_read_series_csv(args.burst_flow_csv), + normal_flow=_read_series_csv(args.normal_flow_csv), + min_dpressure=args.min_dpressure, + basic_pressure=args.basic_pressure, + n_workers=args.n_workers, + final_candidates_csv_path=args.final_candidates_csv_path, + ) + print(json.dumps(result, ensure_ascii=False)) + + +if __name__ == "__main__": + main() diff --git a/app/algorithms/burst_location/burst_locator.py b/app/algorithms/burst_location/burst_locator.py new file mode 100644 index 0000000..dd5906c --- /dev/null +++ b/app/algorithms/burst_location/burst_locator.py @@ -0,0 +1,772 @@ +"""爆管定位主模块。""" + +import copy +import math +import os +import sys +from datetime import datetime +from time import perf_counter + +import networkx as nx +import numpy as np +import pandas as pd + +from .leak_simulator import cal_signature_pipe_multi_pf +from .network_partitioner import ( + cal_group_num, + metis_grouping_pipe_weight, + visualize_metis_partition, +) +from .similarity_calculator import ( + adjust_ratio, + cal_similarity_all_multi_new_sq_improve_double_lzr, + decode_mode, + extra_judge, + update_similarity, +) + + +def _ensure_signatures_for_centers( + wn, + wn_inp_path, + center_list, # 本轮要用到的中心(list[str]) + pressure_leak_all, + flow_leak_all, # 全量缓存(可为空 DF) + timestep_list, # 你现有的时序列表 + pressure_monitor, + flow_monitor, # 用来推断传感器列名 + leak_mag, + n_workers=1, +): + """ + 只为缺失的中心补算 SLF(调用你现有的 cal_signature_pipe_multi_pf), + 并把补算结果并回缓存。返回: + pressure_leak_subset, flow_leak_subset, pressure_leak_all_new, flow_leak_all_new + 其中 subset 只包含 center_list 的行(顺序与 center_list 保持一致)。 + """ + + center_list = _dedupe_preserve_order(center_list) + + # 1) 推断传感器列名(与现有数据保持一致) + sensor_name_all = list(pressure_monitor.columns) + sensor_f_name_all = ( + list(flow_monitor.columns) + if (flow_monitor is not None and hasattr(flow_monitor, "columns")) + else [] + ) + + # 2) 取出缓存里已经有的中心(考虑 MultiIndex 的第 0 层为 pipe) + def _existing_pipes(df): + if df is None or len(df) == 0: + return set() + idx = df.index + if isinstance(idx, pd.MultiIndex): + return set(idx.get_level_values(0)) + else: + return set(idx) + + exist_p = _existing_pipes(pressure_leak_all) + need = [p for p in center_list if p not in exist_p] + + # 3) 若有缺失中心,仅为这些中心补算一次 + if len(need) > 0: + p_new, _ = cal_signature_pipe_multi_pf( + wn, + leak_mag, + need, + timestep_list, + sensor_name_all, + n_workers=n_workers, + wn_inp_path=wn_inp_path, + ) + # 初始化空缓存时,做一次“同构化” + if pressure_leak_all is None or len(pressure_leak_all) == 0: + pressure_leak_all = p_new + else: + pressure_leak_all = pd.concat([pressure_leak_all, p_new], axis=0) + # if (flow_leak_all is None or len(flow_leak_all) == 0) and f_new is not None: + # flow_leak_all = f_new + # elif f_new is not None: + # flow_leak_all = pd.concat([flow_leak_all, f_new], axis=0) + + # 去重(如果既有缓存里不小心有重复中心) + if isinstance(pressure_leak_all.index, pd.MultiIndex): + pressure_leak_all = pressure_leak_all[ + ~pressure_leak_all.index.duplicated(keep="last") + ] + if flow_leak_all is not None and len(flow_leak_all) > 0: + flow_leak_all = flow_leak_all[ + ~flow_leak_all.index.duplicated(keep="last") + ] + else: + pressure_leak_all = pressure_leak_all[ + ~pressure_leak_all.index.duplicated(keep="last") + ] + if flow_leak_all is not None and len(flow_leak_all) > 0: + flow_leak_all = flow_leak_all[ + ~flow_leak_all.index.duplicated(keep="last") + ] + + # 4) 从更新后的缓存里,取出这轮需要的中心子集(顺序与 center_list 一致) + if isinstance(pressure_leak_all.index, pd.MultiIndex): + pressure_subset = pressure_leak_all.loc[center_list] + flow_subset = ( + flow_leak_all.loc[center_list] + if (flow_leak_all is not None and len(flow_leak_all) > 0) + else None + ) + else: + pressure_subset = pressure_leak_all.loc[center_list, :] + flow_subset = ( + flow_leak_all.loc[center_list, :] + if (flow_leak_all is not None and len(flow_leak_all) > 0) + else None + ) + + return pressure_subset, flow_subset, pressure_leak_all, flow_leak_all + + +def area_output_num_ki_improve( + candidate_center, + candidate_group, + similarity, + new_all_node, + top_group_ratio, + top_pipe_num_max, + top_pipe_num_min, + cut_ratio, +): + final_area = [] + final_center = [] + all_node_iter = [] + if similarity.index.is_unique == False: + total_center_num = len(set(similarity.index)) + else: + total_center_num = len(similarity.index) + + next_group_num = min( + total_center_num, math.ceil(total_center_num / cut_ratio * top_group_ratio) + ) + + for i in range(next_group_num): + top_center = similarity.index[i] + top_center_index = find_list_repeat(candidate_center, top_center) + for j in range(len(top_center_index)): + final_area = final_area + candidate_group[top_center_index[j]] + all_node_iter = all_node_iter + list(new_all_node[top_center_index[j]]) + final_center.append(top_center) + final_area = sorted(set(final_area)) + + if len(final_area) > top_pipe_num_max: + if_end = 0 + elif len(final_area) > top_pipe_num_min: + if_end = 1 + elif total_center_num == next_group_num: + if_end = 1 + else: + if_end = 1 + for i in np.arange(next_group_num, total_center_num, 1): + + before_list = copy.deepcopy(final_area) + top_center = similarity.index[i] + top_center_index = candidate_center.index(top_center) + temp_group = final_area + candidate_group[top_center_index] + temp_area = sorted(set(temp_group)) + + if len(temp_area) < top_pipe_num_min: + + final_center.append(top_center) + all_node_iter = all_node_iter + list(new_all_node[top_center_index]) + final_area = temp_area + + elif len(temp_area) < top_pipe_num_max: + final_center.append(top_center) + all_node_iter = all_node_iter + list(new_all_node[top_center_index]) + final_area = temp_area + break + else: + a = len(temp_area) - top_pipe_num_max + b = top_pipe_num_min - len(before_list) + + if a >= b: + final_area = before_list + else: + final_center.append(top_center) + all_node_iter = all_node_iter + list(new_all_node[top_center_index]) + final_area = temp_area + break + + final_center = sorted(set(final_center)) + all_node_iter = sorted(set(all_node_iter)) + return final_area, final_center, all_node_iter, if_end + + +def find_list_repeat(candidate_center, target): + repeated_list = [] + for index, nums in enumerate(candidate_center): + if nums == target: + repeated_list.append(index) + return repeated_list + + +def _dedupe_preserve_order(items): + seen = set() + output = [] + for item in items: + if item in seen: + continue + seen.add(item) + output.append(item) + return output + + +def _accumulate_stage(stage_timing, stage_name, started_at): + stage_timing[stage_name] = stage_timing.get(stage_name, 0.0) + ( + perf_counter() - started_at + ) + + +def _write_last_round_candidates_csv( + csv_path, + exit_condition, + iteration_count, + similarity_mode, + candidate_details, + fallback_similarity, +): + if not csv_path: + return None + timestamp_suffix = datetime.now().strftime("%Y%m%d_%H%M%S") + base_path, ext = os.path.splitext(csv_path) + ext = ext or ".csv" + output_path = f"{base_path}_{timestamp_suffix}{ext}" + if candidate_details is not None and len(candidate_details) > 0: + export_df = candidate_details.copy() + if export_df.index.name == "pipe_id": + export_df = export_df.reset_index() + else: + export_df = pd.DataFrame( + { + "pipe_id": [str(pipe_id) for pipe_id in fallback_similarity.index], + "final_similarity": [float(value) for value in fallback_similarity.values], + } + ) + export_df["exit_condition"] = exit_condition + export_df["iterations"] = int(iteration_count) + export_df["similarity_mode"] = similarity_mode + parent_dir = os.path.dirname(output_path) + if parent_dir: + os.makedirs(parent_dir, exist_ok=True) + export_df.to_csv(output_path, index=False, encoding="utf-8-sig") + return output_path + + +def cal_DtoTop1( + G0, pipe_leak, located_pipe, pipe_start_node_all, pipe_end_node_all, pipe_length +): + if pipe_leak == located_pipe: + result_DtoTop1 = 0 + result_DtoTop1_num = 0 + else: + pipe_leak_start_node = pipe_start_node_all[pipe_leak] + pipe_leak_end_node = pipe_end_node_all[pipe_leak] + located_pipe_start_node = pipe_start_node_all[located_pipe] + located_pipe_end_node = pipe_end_node_all[located_pipe] + DtoTop1_series = pd.Series(dtype=object) + DtoTop1_num_series = pd.Series(dtype=object) + DtoTop1_series["ss"] = nx.shortest_path_length( + G0, pipe_leak_start_node, located_pipe_start_node, weight="weight" + ) + DtoTop1_series["se"] = nx.shortest_path_length( + G0, pipe_leak_start_node, located_pipe_end_node, weight="weight" + ) + DtoTop1_series["es"] = nx.shortest_path_length( + G0, pipe_leak_end_node, located_pipe_start_node, weight="weight" + ) + DtoTop1_series["ee"] = nx.shortest_path_length( + G0, pipe_leak_end_node, located_pipe_end_node, weight="weight" + ) + DtoTop1_num_series["ss"] = nx.shortest_path_length( + G0, pipe_leak_start_node, located_pipe_start_node + ) + DtoTop1_num_series["se"] = nx.shortest_path_length( + G0, pipe_leak_start_node, located_pipe_end_node + ) + DtoTop1_num_series["es"] = nx.shortest_path_length( + G0, pipe_leak_end_node, located_pipe_start_node + ) + DtoTop1_num_series["ee"] = nx.shortest_path_length( + G0, pipe_leak_end_node, located_pipe_end_node + ) + + if DtoTop1_num_series.min() == 0: + result_DtoTop1_num = 1 + result_DtoTop1 = DtoTop1_series.max() / 2 + else: + result_DtoTop1_num = DtoTop1_num_series.min() + 1 + DtoTop1_type = DtoTop1_series.argmin() + result_DtoTop1 = ( + DtoTop1_series[DtoTop1_type] + + (pipe_length[pipe_leak] + pipe_length[located_pipe]) / 2 + ) + return result_DtoTop1, result_DtoTop1_num + + +def cal_RR(located_pipe, similarity_sp): + if located_pipe in similarity_sp.index: + rank = similarity_sp.index.get_loc(located_pipe) + RR = rank / len(similarity_sp.index) + else: + RR = 1.1 + return RR + + +def cal_cover(similarity, leak_pipe): + if leak_pipe in list(similarity.index): + cover = 1 + else: + cover = 0 + return cover + + +def cal_SD(located_pipe, real_pipe, pipe_x, pipe_y): + dx = pipe_x[located_pipe] - pipe_x[real_pipe] + dy = pipe_y[located_pipe] - pipe_y[real_pipe] + SD = math.sqrt(dx * dx + dy * dy) + return SD + + +def DN_search_multi_simple_add_flow_count_new( + wn, + wn_inp_path, + G0, + all_node, + node_x, + node_y, + pipe_start_node_all, + pipe_end_node_all, + pipe_diameter, + couple_node_length, + node_pipe_dic, + all_node_series, + top_group_ratio, + top_pipe_num_max, + top_pipe_num_min, + candidate_pipe_input_initial, + similarity_mode, + pressure_monitor, + pressure_predict, + pressure_normal, + pressure_leak_all, + flow_monitor, + flow_predict, + flow_normal, + flow_leak_all, + timestep_list, + max_flow, + group_basic_num, + Top_sensor_num, + if_gy, + pressure_threshold, + leak_mag, + n_workers=1, + stage_timing=None, + partition_on_full_graph=True, + visualize_partition=False, + visualize_pause_seconds=0.3, + final_candidates_csv_path=None, +): + if stage_timing is None: + stage_timing = {} + exit_condition = "unknown" + final_candidates_csv = None + iter_count = 0 + all_node_iter = copy.deepcopy(all_node) + candidate_pipe_input = copy.deepcopy(candidate_pipe_input_initial) # 可能漏损管段 + t1 = datetime.now() + if_flow, if_only_cos, if_only_flow = decode_mode(similarity_mode) # 定位方法 + # threshold + if if_only_flow == 1: + dpressure = (flow_predict - flow_monitor).mean() + dpressure = dpressure.abs() + effective_sensor = list(dpressure.index) + + else: + dpressure = (pressure_predict - pressure_monitor).mean() + dpressure = dpressure.abs() + dpressure = dpressure[dpressure > pressure_threshold] + effective_sensor = list(dpressure.index) + simulation_times = 0 # 模拟次数 + if len(dpressure) > 0: + break_flag = 0 + last_round_candidate_details = None + + cos_h = 0 + dis_h = 0 + dis_f_h = 0 + if_compalsive = 0 + record_center_dataset = [] + record_center_set = set() + # iter + while 1: + final_area = [] + final_center = [] + group_num = cal_group_num(candidate_pipe_input, group_basic_num) + partition_nodes = all_node if partition_on_full_graph else all_node_iter + + # group 分组,得出候选漏损中心 + stage_start = perf_counter() + ( + candidate_center_list, + candidate_group_list, + new_all_node, + candidate_center_candidates, + ) = ( + metis_grouping_pipe_weight( + G0, + wn, + partition_nodes, + candidate_pipe_input, + group_num, + node_x, + node_y, + pipe_start_node_all, + pipe_end_node_all, + node_pipe_dic, + all_node_series, + couple_node_length, + pipe_diameter, + ) + ) + _accumulate_stage(stage_timing, "group_partitioning", stage_start) + if visualize_partition: + visualize_metis_partition( + G0, + candidate_center_list, + candidate_group_list, + node_x, + node_y, + pipe_start_node_all, + pipe_end_node_all, + title=( + f"METIS Partition Iteration {iter_count + 1} | " + f"candidate pipes={len(candidate_pipe_input)} " + f"groups={len(candidate_group_list)}" + ), + block=False, + pause_seconds=visualize_pause_seconds, + ) + simulation_times = simulation_times + len(candidate_center_list) + # pick_pressure_leak + # pressure_leak = pressure_leak_all.loc[candidate_center_list].loc[:, :] + # flow_leak = flow_leak_all.loc[candidate_center_list].loc[:, :] + # —— 新增泄漏量(保持你现在的一致,或从外部传入)—— + # —— 只为缺失中心补算,然后取本轮需要的中心子集 —— + stage_start = perf_counter() + pressure_leak, flow_leak, pressure_leak_all, flow_leak_all = ( + _ensure_signatures_for_centers( + wn=wn, + wn_inp_path=wn_inp_path, + center_list=candidate_center_list, + pressure_leak_all=pressure_leak_all, + flow_leak_all=flow_leak_all, + timestep_list=timestep_list, + pressure_monitor=pressure_monitor, + flow_monitor=flow_monitor, + leak_mag=leak_mag, + n_workers=n_workers, + ) + ) + _accumulate_stage(stage_timing, "signature_for_candidates", stage_start) + + # pressure_leak_f= pressure_leak.swaplevel() + + # -------------------------------------------------------- + + add_center = [] + leak_center_dict = dict() + for i in range(len(candidate_center_list)): + primary_center = candidate_center_list[i] + houxuan_center = [ + center + for center in candidate_center_candidates[i] + if center != primary_center + ] + candidate_group_set = set(candidate_group_list[i]) + for each_center in record_center_dataset: + if ( + each_center in candidate_group_set + and each_center != primary_center + ): + houxuan_center.append(each_center) + add_center = add_center + houxuan_center + leak_center_dict[primary_center] = _dedupe_preserve_order( + houxuan_center + [primary_center] + ) + add_center = _dedupe_preserve_order(add_center) + for each_group_centers in candidate_center_candidates: + for each_center in each_group_centers: + if each_center not in record_center_set: + record_center_dataset.append(each_center) + record_center_set.add(each_center) + for each_center in add_center: + if each_center not in record_center_set: + record_center_dataset.append(each_center) + record_center_set.add(each_center) + + # -------------------------------------------------------- + # -------------------------------------------------------- + # if len(add_center) > 0: + # s3 = pressure_leak_all.loc[add_center] + # pressure_leak = pd.concat([pressure_leak, s3]) + # s4 = flow_leak_all.loc[add_center] + # flow_leak = pd.concat([flow_leak, s4]) + # -------------------------------------------------------- + # 只为 add_center 里还没算过的中心补算,并与本轮中心合并 + if len(add_center) > 0: + stage_start = perf_counter() + pressure_add, flow_add, pressure_leak_all, flow_leak_all = ( + _ensure_signatures_for_centers( + wn=wn, + wn_inp_path=wn_inp_path, + center_list=add_center, + pressure_leak_all=pressure_leak_all, + flow_leak_all=flow_leak_all, + timestep_list=timestep_list, + pressure_monitor=pressure_monitor, + flow_monitor=flow_monitor, + leak_mag=leak_mag, # 与上面一致 + n_workers=n_workers, + ) + ) + _accumulate_stage( + stage_timing, "signature_for_extra_centers", stage_start + ) + pressure_leak = pd.concat([pressure_leak, pressure_add], axis=0) + if (flow_leak is not None) and (flow_add is not None): + flow_leak = pd.concat([flow_leak, flow_add], axis=0) + # -------------------------------------------------------- + # + if len(candidate_pipe_input) < 1.2 * top_pipe_num_max / top_group_ratio: + if_compalsive = 1 + cos_h, dis_h, dis_f_h = adjust_ratio(similarity_mode, cos_h, dis_h, dis_f_h) + candidate_center_list_sup = _dedupe_preserve_order( + candidate_center_list + add_center + ) + stage_start = perf_counter() + similarity, cos_h, dis_h, dis_f_h, break_flag, similarity_details = ( + cal_similarity_all_multi_new_sq_improve_double_lzr( + candidate_center_list_sup, + similarity_mode, + pressure_leak, + pressure_monitor, + pressure_predict, + pressure_normal, + if_flow, + if_only_cos, + if_only_flow, + flow_leak, + flow_monitor, + flow_predict, + flow_normal, + timestep_list, + Top_sensor_num, + if_gy, + effective_sensor, + cos_h, + dis_h, + dis_f_h, + if_compalsive, + max_flow, + ) + ) + last_round_candidate_details = similarity_details + _accumulate_stage(stage_timing, "similarity_ranking", stage_start) + if break_flag == 1: + exit_condition = "similarity_break_flag" + break + + new_similarity = update_similarity( + candidate_center_list, similarity, leak_center_dict + ) + if len(candidate_pipe_input) > top_pipe_num_max / top_group_ratio: + cut_ratio, new_similarity = extra_judge(new_similarity) + else: + cut_ratio = 1 + stage_start = perf_counter() + final_area_t, final_center_t, all_node_new_1, if_end = ( + area_output_num_ki_improve( + candidate_center_list, + candidate_group_list, + new_similarity, + new_all_node, + top_group_ratio, + top_pipe_num_max, + top_pipe_num_min, + cut_ratio, + ) + ) + _accumulate_stage(stage_timing, "candidate_area_selection", stage_start) + final_area = final_area + final_area_t + final_center = final_center + final_center_t + + final_area = sorted(set(final_area)) + final_center = sorted(set(final_center)) + if if_end == 1: + exit_condition = "candidate_area_if_end" + break + elif len(candidate_pipe_input) == len(final_area): + exit_condition = "candidate_size_no_change" + break + else: + candidate_pipe_input = final_area + if not partition_on_full_graph: + all_node_iter = all_node_new_1 + iter_count += 1 + sys.stdout.write( + "\r" + + "已经完成" + + str(iter_count) + + "次迭代计算" + + "候选节点" + + str(len(final_area)) + + "个" + ) + # if break_flag == 0: + # final_area_pipe = copy.deepcopy(final_area) + # simulation_times = simulation_times + len(final_area) + # pressure_leak_sp = pressure_leak_all.loc[final_area_pipe].loc[:, :] + # flow_leak_sp = flow_leak_all.loc[final_area_pipe].loc[:, :] + # similarity_sp, cos_h, dis_h, dis_f_h, break_flag = cal_similarity_all_multi_new_sq_improve_double_lzr( + # final_area_pipe, similarity_mode, pressure_leak_sp, + # pressure_monitor, pressure_predict, pressure_normal, if_flow, + # if_only_cos, if_only_flow, + # flow_leak_sp, flow_monitor, flow_predict, flow_normal, + # timestep_list, Top_sensor_num, if_gy, effective_sensor, cos_h, dis_h, dis_f_h, if_compalsive, max_flow) + if break_flag == 0: + final_area_pipe = list(final_area) # 确保是 list + + # 只为还没算过的管段补齐 SLF(按需计算) + stage_start = perf_counter() + pressure_leak_sp, flow_leak_sp, pressure_leak_all, flow_leak_all = ( + _ensure_signatures_for_centers( + wn=wn, + wn_inp_path=wn_inp_path, + center_list=final_area_pipe, # 这次要用的“最终区域里的所有管段” + pressure_leak_all=pressure_leak_all, # 累积缓存(会被更新) + flow_leak_all=flow_leak_all, + timestep_list=timestep_list, + pressure_monitor=pressure_monitor, + flow_monitor=flow_monitor, + leak_mag=leak_mag, + n_workers=n_workers, + ) + ) + _accumulate_stage(stage_timing, "signature_for_final_area", stage_start) + + # 如果你要精确统计模拟次数,这里可以加上“本次新补的数量”, + # 做法:让 _ensure_signatures_for_centers 额外返回 need_cnt,再 simulation_times += need_cnt + + stage_start = perf_counter() + ( + similarity_sp, + cos_h, + dis_h, + dis_f_h, + break_flag, + similarity_details, + ) = ( + cal_similarity_all_multi_new_sq_improve_double_lzr( + final_area_pipe, + similarity_mode, + pressure_leak_sp, + pressure_monitor, + pressure_predict, + pressure_normal, + if_flow, + if_only_cos, + if_only_flow, + flow_leak_sp, + flow_monitor, + flow_predict, + flow_normal, + timestep_list, + Top_sensor_num, + if_gy, + effective_sensor, + cos_h, + dis_h, + dis_f_h, + if_compalsive, + max_flow, + ) + ) + last_round_candidate_details = similarity_details + _accumulate_stage(stage_timing, "similarity_final", stage_start) + + else: + dpressure = (pressure_predict - pressure_monitor).mean() + dpressure = dpressure.abs() + simulation_times = simulation_times + len(dpressure.index) + similarity_sp = pd.Series(dtype=float) + for each_node in dpressure.index: + pipe = node_pipe_dic[each_node][0] + similarity_sp.loc[pipe] = dpressure.loc[each_node] + similarity_sp = similarity_sp.sort_values(ascending=False, kind="mergesort") + t2 = datetime.now() + final_area_pipe = [] + + sys.stdout.write( + "\r" + + "已经完成" + + str(iter_count + 1) + + "次迭代计算" + + "候选节点" + + str(len(final_area_pipe)) + + "个" + ) + t2 = datetime.now() + dt = (t2 - t1).seconds + final_candidates_csv = _write_last_round_candidates_csv( + csv_path=final_candidates_csv_path, + exit_condition=exit_condition, + iteration_count=iter_count + 1, + similarity_mode=similarity_mode, + candidate_details=last_round_candidate_details, + fallback_similarity=similarity_sp, + ) + else: + exit_condition = "no_effective_sensor_after_threshold" + dpressure = (pressure_predict - pressure_monitor).mean() + dpressure = dpressure.abs() + + similarity_sp = pd.Series(dtype=float) + for each_node in dpressure.index: + pipe = node_pipe_dic[each_node][0] + similarity_sp.loc[pipe] = dpressure.loc[each_node] + similarity_sp = similarity_sp.sort_values(ascending=False, kind="mergesort") + t2 = datetime.now() + dt = (t2 - t1).seconds + final_candidates_csv = _write_last_round_candidates_csv( + csv_path=final_candidates_csv_path, + exit_condition=exit_condition, + iteration_count=0, + similarity_mode=similarity_mode, + candidate_details=None, + fallback_similarity=similarity_sp, + ) + stage_timing["iterations"] = iter_count + 1 if len(dpressure) > 0 else 0 + stage_timing["total_elapsed_seconds"] = float(dt) + stage_timing["exit_condition"] = exit_condition + stage_timing["final_candidates_csv"] = final_candidates_csv + return ( + similarity_sp.index[0], + dt, + simulation_times, + wn, + similarity_sp, + exit_condition, + final_candidates_csv, + ) + + diff --git a/app/algorithms/burst_location/leak_simulator.py b/app/algorithms/burst_location/leak_simulator.py new file mode 100644 index 0000000..de3e644 --- /dev/null +++ b/app/algorithms/burst_location/leak_simulator.py @@ -0,0 +1,563 @@ +"""漏损模拟模块。""" + +import math +import multiprocessing as mp +import os +import sys + +import pandas as pd +import wntr + +from app.algorithms._utils import _cleanup_temp_files + +_PIPE2LEAKNODE = None +_SIGNATURE_WORKER_DATA = {} + + +def _make_temp_prefix(tag): + temp_dir = os.path.abspath(os.path.join("temp", "burst_location")) + os.makedirs(temp_dir, exist_ok=True) + safe_tag = str(tag).replace(os.sep, "_").replace(" ", "_") + return os.path.join(temp_dir, f"{safe_tag}_{os.getpid()}") + + +def _snapshot_hydraulic_options(wn): + options = wn.options + return { + "demand_model": options.hydraulic.demand_model, + "duration": float(options.time.duration), + "hydraulic_timestep": float(options.time.hydraulic_timestep), + "pattern_timestep": float(options.time.pattern_timestep), + "report_timestep": float(options.time.report_timestep), + "required_pressure": float(options.hydraulic.required_pressure), + "minimum_pressure": float(options.hydraulic.minimum_pressure), + } + + +def _apply_hydraulic_options(wn, option_values): + options = wn.options + options.hydraulic.demand_model = option_values["demand_model"] + options.time.duration = option_values["duration"] + options.time.hydraulic_timestep = option_values["hydraulic_timestep"] + options.time.pattern_timestep = option_values["pattern_timestep"] + options.time.report_timestep = option_values["report_timestep"] + options.hydraulic.required_pressure = option_values["required_pressure"] + options.hydraulic.minimum_pressure = option_values["minimum_pressure"] + + +def simple_add_leak(wn, leak_mag, leak_pipe): + whole_inf = dict() + leak_pipe_self = wn.get_link(leak_pipe) + pipe_diameter = leak_pipe_self.diameter + pipe_length = leak_pipe_self.length + pipe_roughness = leak_pipe_self.roughness + pipe_minor_loss = leak_pipe_self.minor_loss + # pipe_status = leak_pipe_self.status + # pipe_check_valve = leak_pipe_self.check_valve + pipe_start_node = leak_pipe_self.start_node_name + pipe_end_node = leak_pipe_self.end_node_name + + # close the pipe + # leak_pipe_self.status = 'Closed' + wn.remove_link(leak_pipe) + # add the pipe + add_pipe1 = leak_pipe + "A" + add_pipe2 = leak_pipe + "B" + add_node = leak_pipe + "_" + + start_n = wn.get_node(pipe_start_node) + end_n = wn.get_node(pipe_end_node) + if start_n.node_type == "Reservoir": + end_n_elevation = end_n.elevation + start_n_elevation = end_n_elevation + elif end_n.node_type == "Reservoir": + start_n_elevation = start_n.elevation + end_n_elevation = start_n_elevation + else: + end_n_elevation = end_n.elevation + start_n_elevation = start_n.elevation + elevation_self = (start_n_elevation + end_n_elevation) / 2 + coordinates_self = ( + (start_n.coordinates[0] + end_n.coordinates[0]) / 2, + (start_n.coordinates[1] + end_n.coordinates[1]), + ) + + wn.add_junction( + add_node, base_demand=0, elevation=elevation_self, coordinates=coordinates_self + ) + leak_node = wn.get_node(add_node) + wn.add_pipe( + add_pipe1, + start_node_name=pipe_start_node, + end_node_name=add_node, + length=pipe_length / 2, + diameter=pipe_diameter, + roughness=pipe_roughness, + minor_loss=pipe_minor_loss, + ) + wn.add_pipe( + add_pipe2, + start_node_name=pipe_end_node, + end_node_name=add_node, + length=pipe_length / 2, + diameter=pipe_diameter, + roughness=pipe_roughness, + minor_loss=pipe_minor_loss, + ) + + # simulation + leak_node.add_demand(base=leak_mag, pattern_name="add_leak") + + whole_inf["leak_node_name"] = add_node + whole_inf["add_pipe1"] = add_pipe1 + whole_inf["add_pipe2"] = add_pipe2 + whole_inf["leak_pipe"] = leak_pipe + whole_inf["pipe_start_node"] = pipe_start_node + whole_inf["pipe_end_node"] = pipe_end_node + whole_inf["pipe_length"] = pipe_length + whole_inf["pipe_diameter"] = pipe_diameter + whole_inf["pipe_roughness"] = pipe_roughness + whole_inf["pipe_minor_loss"] = pipe_diameter + return wn, whole_inf, add_pipe1 + + +def simple_recover_wn(wn, whole_inf): + leak_node = wn.get_node(whole_inf["leak_node_name"]) + + del leak_node.demand_timeseries_list[-1] + # update + wn.remove_link(whole_inf["add_pipe1"]) + wn.remove_link(whole_inf["add_pipe2"]) + wn.remove_node(whole_inf["leak_node_name"]) + # open the pipe + # leak_pipe_self.status = 'Open' + wn.add_pipe( + whole_inf["leak_pipe"], + start_node_name=whole_inf["pipe_start_node"], + end_node_name=whole_inf["pipe_end_node"], + length=whole_inf["pipe_length"], + diameter=whole_inf["pipe_diameter"], + roughness=whole_inf["pipe_roughness"], + minor_loss=whole_inf["pipe_minor_loss"], + ) + + return wn + + +def disable_all_controls_temporarily(wn): + """返回(控制名, 控制对象)的列表,之后可用 restore_controls 还原。""" + removed = [] + # WNTR 的控制都在 wn.control_name_list / wn.get_control / wn.remove_control + for cname in list(wn.control_name_list): + ctrl = wn.get_control(cname) + removed.append((cname, ctrl)) + wn.remove_control(cname) + return removed + + +def restore_controls(wn, removed): + """把先前禁用的控制全部加回去。""" + for cname, ctrl in removed: + wn.add_control(cname, ctrl) + + +def set_pipe2leaknode_mapping(mapping): + global _PIPE2LEAKNODE + _PIPE2LEAKNODE = mapping + + +def _get_or_create_leak_demand_ts(leak_node): + """ + 返回:泄漏专用 demand 的下标 idx。 + 若不存在,以 category='leak' 新建一条 base=0.0 的 demand。 + """ + # 先尝试找到已有的 'leak' 分类 + for i, ts in enumerate(leak_node.demand_timeseries_list): + # WNTR 的 Demand object 存在 category 属性 + if getattr(ts, "category", None) == "leak": + return i + # 没有则新建(base=0.0,后续临时改 base_value) + leak_node.add_demand(base=0.0, pattern_name=None, category="leak") + return len(leak_node.demand_timeseries_list) - 1 + + +def ensure_mid_node(wn, leak_pipe): + add_pipe1 = f"{leak_pipe}A" + add_pipe2 = f"{leak_pipe}B" + add_node = f"{leak_pipe}__mid" + + if add_node in wn.node_name_list: + return add_node + + if leak_pipe in wn.link_name_list: + leak_pipe_self = wn.get_link(leak_pipe) + pipe_diameter = leak_pipe_self.diameter + pipe_length = leak_pipe_self.length + pipe_roughness = leak_pipe_self.roughness + pipe_minor_loss = leak_pipe_self.minor_loss + pipe_start_node = leak_pipe_self.start_node_name + pipe_end_node = leak_pipe_self.end_node_name + + start_n = wn.get_node(pipe_start_node) + end_n = wn.get_node(pipe_end_node) + if start_n.node_type == "Reservoir": + end_elev = end_n.elevation + start_elev = end_elev + elif end_n.node_type == "Reservoir": + start_elev = start_n.elevation + end_elev = start_elev + else: + end_elev = end_n.elevation + start_elev = start_n.elevation + elev_mid = (start_elev + end_elev) / 2.0 + x_mid = (start_n.coordinates[0] + end_n.coordinates[0]) / 2.0 + y_mid = (start_n.coordinates[1] + end_n.coordinates[1]) / 2.0 + + wn.remove_link(leak_pipe) + wn.add_junction( + add_node, base_demand=0.0, elevation=elev_mid, coordinates=(x_mid, y_mid) + ) + wn.add_pipe( + add_pipe1, + start_node_name=pipe_start_node, + end_node_name=add_node, + length=pipe_length / 2.0, + diameter=pipe_diameter, + roughness=pipe_roughness, + minor_loss=pipe_minor_loss, + ) + wn.add_pipe( + add_pipe2, + start_node_name=add_node, + end_node_name=pipe_end_node, + length=pipe_length / 2.0, + diameter=pipe_diameter, + roughness=pipe_roughness, + minor_loss=pipe_minor_loss, + ) + return add_node + + # 若 A/B 已存在但中点不在,建议确认网络一致性 + raise KeyError(f"Cannot ensure mid node for pipe '{leak_pipe}'.") + + +def leak_simulation_pipe_dd_multi_pf( + wn, leak_mag, leak_pipe, sensor_name, file_prefix=None +): + """ + 优化版: + - 不再 remove/add link/node + - 直接在预插入的中点泄漏节点上设置 base_demand = leak_mag;仿真后设回 0 + """ + wn.options.hydraulic.demand_model = "DD" + + # 确保中点节点存在 + leak_node_name = ensure_mid_node(wn, leak_pipe) + leak_node = wn.get_node(leak_node_name) + + # 拿到泄漏专用的 demand time-series 下标 + leak_idx = _get_or_create_leak_demand_ts(leak_node) + ts_obj = leak_node.demand_timeseries_list[leak_idx] + + # 记录原值(通常是 0.0) + orig_base = ts_obj.base_value + try: + # 打开泄漏:只改 base_value,不碰 base_demand(只读) + ts_obj.base_value = float(leak_mag) + + # 仿真 + sim = wntr.sim.EpanetSimulator(wn) + if file_prefix is None: + results = sim.run_sim() + else: + results = sim.run_sim(file_prefix=file_prefix) + + # 输出(保持列顺序) + pressure_output = results.node["pressure"].loc[:, sensor_name] + # flow_output = results.link['flowrate'].loc[:, sensor_f_name] + return wn, pressure_output + finally: + # 关闭泄漏:还原 base_value + ts_obj.base_value = orig_base + if file_prefix is not None: + _cleanup_temp_files(file_prefix) + + +def prepare_leak_infrastructure(wn, candidate_pipes): + """ + 把 candidate_pipes 每条管段切成两段,并在中点插入一个泄漏节点(base_demand=0)。 + 返回一个映射:pipe_id -> leak_node_name + 注意:只做一次;后续仿真通过在该节点设置 base_demand 实现“打开泄漏”,结束后恢复为 0。 + """ + pipe2leaknode = {} + for leak_pipe in candidate_pipes: + if leak_pipe in pipe2leaknode: + continue + + leak_pipe_self = wn.get_link(leak_pipe) + pipe_diameter = leak_pipe_self.diameter + pipe_length = leak_pipe_self.length + pipe_roughness = leak_pipe_self.roughness + pipe_minor_loss = leak_pipe_self.minor_loss + pipe_start_node = leak_pipe_self.start_node_name + pipe_end_node = leak_pipe_self.end_node_name + + # 计算中点高程/坐标(与原逻辑一致) + start_n = wn.get_node(pipe_start_node) + end_n = wn.get_node(pipe_end_node) + if start_n.node_type == "Reservoir": + end_elev = end_n.elevation + start_elev = end_elev + elif end_n.node_type == "Reservoir": + start_elev = start_n.elevation + end_elev = start_elev + else: + end_elev = end_n.elevation + start_elev = start_n.elevation + elev_mid = (start_elev + end_elev) / 2.0 + x_mid = (start_n.coordinates[0] + end_n.coordinates[0]) / 2.0 + y_mid = (start_n.coordinates[1] + end_n.coordinates[1]) / 2.0 + + # 先删原管,再加中点与两段半长管(只做一次) + wn.remove_link(leak_pipe) + + add_pipe1 = f"{leak_pipe}A" + add_pipe2 = f"{leak_pipe}B" + add_node = f"{leak_pipe}__mid" # 唯一命名,后面直接用它当泄漏节点 + + wn.add_junction( + add_node, base_demand=0.0, elevation=elev_mid, coordinates=(x_mid, y_mid) + ) + wn.add_pipe( + add_pipe1, + start_node_name=pipe_start_node, + end_node_name=add_node, + length=pipe_length / 2.0, + diameter=pipe_diameter, + roughness=pipe_roughness, + minor_loss=pipe_minor_loss, + ) + wn.add_pipe( + add_pipe2, + start_node_name=add_node, + end_node_name=pipe_end_node, + length=pipe_length / 2.0, + diameter=pipe_diameter, + roughness=pipe_roughness, + minor_loss=pipe_minor_loss, + ) + + pipe2leaknode[leak_pipe] = add_node + + return pipe2leaknode + + +def normal_simulation_pf( + wn, drive_mode, sensor_name, sensor_f_name, inp_time, require_p, minimum_p +): + # inp_time = 0 + if drive_mode == "PDD": # 需水量根据节点压力动态调整 + wn.options.hydraulic.demand_model = "PDD" + wn.options.hydraulic.required_pressure = require_p + wn.options.hydraulic.minimum_pressure = minimum_p + elif drive_mode == "DD": # 需水量固定,与压力无关 + wn.options.hydraulic.demand_model = "DD" + sim = wntr.sim.EpanetSimulator(wn) + results = sim.run_sim() + pressure_all = results.node["pressure"][sensor_name] + pressure = pressure_all.iloc[inp_time] + demand_all = results.node["demand"] + demand = demand_all.iloc[inp_time] + sum_demand = cal_sum_demand(demand) + flow_all = results.link["flowrate"][sensor_f_name] + flow = flow_all.iloc[inp_time] + + top_sensor = pressure.idxmin() + basic_p = results.node["pressure"] + basic_p = basic_p.iloc[inp_time] + return pressure, flow, basic_p, top_sensor, sum_demand + + +def normal_simulation_multi_pf( + wn, drive_mode, sensor_name, sensor_f_name, require_p, minimum_p +): + # inp_time = 0 + if drive_mode == "PDD": + wn.options.hydraulic.demand_model = "PDD" + wn.options.hydraulic.required_pressure = require_p + wn.options.hydraulic.minimum_pressure = minimum_p + elif drive_mode == "DD": + wn.options.hydraulic.demand_model = "DD" + sim = wntr.sim.EpanetSimulator(wn) + results = sim.run_sim() + pressure_all = results.node["pressure"][sensor_name] + pressure = pressure_all + demand_all = results.node["demand"] + demand = demand_all + flow = results.link["flowrate"][sensor_f_name] + sum_demand = pd.Series(dtype=object) + for i in range(len(demand.index)): + sum_demand[str(demand.index[i])] = cal_sum_demand(demand.iloc[i]) + if type(pressure) == pd.core.series.Series: + top_sensor = pressure.idxmin() + else: + mean_pressure = pressure.mean() + top_sensor = mean_pressure.idxmin() + basic_p = results.node["pressure"] + return pressure, flow, basic_p, top_sensor, sum_demand + + +def simple_simulation_pf(wn, sensor_name, sensor_f_name, leak_pipe, add_pipe1): + sim = wntr.sim.EpanetSimulator(wn) + results = sim.run_sim() + pressure_all = results.node["pressure"][sensor_name] + if len(leak_pipe) > 0 and leak_pipe in sensor_f_name: + + f_sensor_name = [add_pipe1 if i == leak_pipe else i for i in sensor_f_name] + flow_all = results.link["flowrate"][f_sensor_name] + flow_all.columns = sensor_f_name + else: + flow_all = results.link["flowrate"][sensor_f_name] + return pressure_all, flow_all + + +def cal_sum_demand(demand): + sum_demand = 0 + for i in range(len(demand)): + if demand.iloc[i] > 0: + sum_demand += demand.iloc[i] + return sum_demand + + +def cal_signature_pipe_multi_pf( + wn, + leak_mag, + candidate_center, + timestep_list, + sensor_name, + n_workers=1, + wn_inp_path=None, +): + candidate_center_num = len(candidate_center) + pressure_leak = pd.DataFrame( + index=pd.MultiIndex.from_product([candidate_center, timestep_list]), + columns=sensor_name, + ) + # flow_leak = pd.DataFrame(index=pd.MultiIndex.from_product([candidate_center, timestep_list]), + # columns=sensor_f_name) + pressure_leak = pressure_leak.sort_index() + # flow_leak = flow_leak.sort_index() + can_parallel = ( + n_workers > 1 + and candidate_center_num > 1 + and wn_inp_path is not None + and len(str(wn_inp_path)) > 0 + ) + if can_parallel: + option_values = _snapshot_hydraulic_options(wn) + worker_count = min(n_workers, candidate_center_num) + start_methods = mp.get_all_start_methods() + context_name = "spawn" if "spawn" in start_methods else start_methods[0] + with mp.get_context(context_name).Pool( + processes=worker_count, + initializer=_signature_worker_init, + initargs=( + str(wn_inp_path), + float(leak_mag), + list(sensor_name), + option_values, + list(candidate_center), + ), + ) as pool: + for i, (center_name, pressure_array) in enumerate( + pool.imap(_signature_worker_run_center, candidate_center) + ): + pressure_leak.loc[(center_name, slice(None)), :] = pressure_array + sys.stdout.write("\r" + "已经完成计算" + str(i + 1) + "个特征中心") + else: + # Pre-insert all mid-nodes so every simulation sees the same topology + for center in candidate_center: + ensure_mid_node(wn, center) + for i in range(candidate_center_num): + temp_prefix = _make_temp_prefix(f"sig_{i}") + wn, pressure_output = leak_simulation_pipe_dd_multi_pf( + wn, + leak_mag, + candidate_center[i], + sensor_name, + file_prefix=temp_prefix, + ) + # leak_or_not_list.append(leak_or_not) + pressure_leak.loc[(candidate_center[i], slice(None)), :] = ( + pressure_output.to_numpy() + ) + # flow_leak.loc[candidate_center[i]].loc[:, :] = flow_output + sys.stdout.write("\r" + "已经完成计算" + str(i + 1) + "个特征中心") + return pressure_leak, candidate_center + + +def _signature_worker_init( + inp_path, leak_mag, sensor_name, option_values, candidate_centers=None +): + global _SIGNATURE_WORKER_DATA + wn = wntr.network.WaterNetworkModel(inp_path) + _apply_hydraulic_options(wn, option_values) + # Pre-insert ALL mid-nodes so every simulation runs on the same topology, + # regardless of which worker handles which task. + if candidate_centers is not None: + for center in candidate_centers: + ensure_mid_node(wn, center) + _SIGNATURE_WORKER_DATA = { + "wn": wn, + "leak_mag": leak_mag, + "sensor_name": sensor_name, + } + + +def _signature_worker_run_center(center_name): + data = _SIGNATURE_WORKER_DATA + temp_prefix = _make_temp_prefix(f"sig_worker_{center_name}") + _, pressure_output = leak_simulation_pipe_dd_multi_pf( + data["wn"], + data["leak_mag"], + center_name, + data["sensor_name"], + file_prefix=temp_prefix, + ) + return center_name, pressure_output.to_numpy() + + +def pick_pipe(all_pipes, pipe_diameter, limited_diameter): + candidate_pipe = [] + for each_pipe in all_pipes: + if pipe_diameter[each_pipe] >= limited_diameter: + candidate_pipe.append(each_pipe) + return candidate_pipe + + +def cal_possible_pipe(leak_flow, all_pipe, pipe_diameter): + basic_pressure = 10 # 基础压力 + discharge_coeff = 0.6 # 经验系数 + break_area_ratio = 1 # 爆管面积比 0.5 1.25 + break_area = leak_flow / ( + discharge_coeff * math.sqrt(2 * basic_pressure * 9.81) + ) # 爆管面积 m3/h + """break_area_diameter = math.sqrt(4 * break_area / math.pi) + min_diameter = (math.ceil(1000 * break_area_diameter / break_area_ratio)) / 1000""" + break_area_diameter = math.sqrt( + 4 * break_area / math.pi / break_area_ratio + ) # 爆管直径 + min_diameter = (math.ceil(1000 * break_area_diameter)) / 1000 # 向上取整 + new_all_pipe = pick_pipe(all_pipe, pipe_diameter, min_diameter) + return new_all_pipe, min_diameter + + +def extract_links(data, link_types, direction): + return [ + link + for res_data in data.values() + for link_type in link_types + for link in res_data[link_type][direction] + ] + + diff --git a/app/algorithms/burst_location/network_model.py b/app/algorithms/burst_location/network_model.py new file mode 100644 index 0000000..2f73632 --- /dev/null +++ b/app/algorithms/burst_location/network_model.py @@ -0,0 +1,137 @@ +"""管网模型读取与图构建模块。""" + +import copy + +import numpy as np +import networkx as nx +import pandas as pd +import wntr + + +def load_inp(inp_name, inp_location, inp_time, driven_mode, require_p, minimum_p): + inp_file = inp_location + inp_name + wn = wntr.network.WaterNetworkModel(inp_file) + if driven_mode == "PDD": + wn.options.hydraulic.demand_model = "PDD" + wn.options.hydraulic.required_pressure = require_p + wn.options.hydraulic.minimum_pressure = minimum_p + else: + wn.options.hydraulic.demand_model = "DD" + return wn + + +def read_inf_inp(wn): + all_node = wn.node_name_list + node_elevation = wn.query_node_attribute("elevation") + node_coordinates = wn.query_node_attribute("coordinates") + + all_pipe = wn.pipe_name_list + # 改_wz__________________________________ + n_pipe = [] + for p in all_pipe: + pipe = wn.get_link(p) + if pipe.initial_status == 0: # 状态为'Closed' + n_pipe.append(p) + candidate_pipe_init = sorted(set(all_pipe) - set(n_pipe)) + pipe_start_node = wn.query_link_attribute( + "start_node_name", link_type=wntr.network.model.Pipe + ) + pipe_end_node = wn.query_link_attribute( + "end_node_name", link_type=wntr.network.model.Pipe + ) + pipe_length = wn.query_link_attribute("length") + pipe_diameter = wn.query_link_attribute("diameter") + + return ( + all_node, + node_elevation, + node_coordinates, + candidate_pipe_init, + pipe_start_node, + pipe_end_node, + pipe_length, + pipe_diameter, + ) + + +def read_inf_inp_other(wn): + all_link = wn.link_name_list + pipe_start_node_all = wn.query_link_attribute("start_node_name") + pipe_end_node_all = wn.query_link_attribute("end_node_name") + + return all_link, pipe_start_node_all, pipe_end_node_all + + +def construct_graph(wn): + length = wn.query_link_attribute("length") + G = wn.get_graph(wn, link_weight=length) + # 转为无向图 + G0 = G.to_undirected() + # A0 = np.array(nx.adjacency_graph(G0).todense()) + return G0 # , A0 + + +def cal_pipe_coordinate(all_pipe, pipe_start_node, pipe_end_node, node_coordinates): + pipe_num = len(all_pipe) + pipe_coordinates = np.zeros([pipe_num, 2]) + pipe_x = copy.deepcopy(pipe_start_node) + pipe_y = copy.deepcopy(pipe_start_node) + for i in range(pipe_num): + temp_pipe = all_pipe[i] + pipe_x[temp_pipe] = ( + node_coordinates[pipe_start_node[temp_pipe]][0] + + node_coordinates[pipe_end_node[temp_pipe]][0] + ) / 2 + pipe_y[temp_pipe] = ( + node_coordinates[pipe_start_node[temp_pipe]][1] + + node_coordinates[pipe_end_node[temp_pipe]][1] + ) / 2 + return pipe_x, pipe_y + + +def cal_node_coordinate(all_node, node_coordinates): + node_x = copy.deepcopy(node_coordinates) + node_y = copy.deepcopy(node_coordinates) + for i in range(len(node_x)): + temp_node = all_node[i] + node_x[temp_node] = node_coordinates[temp_node][0] + node_y[temp_node] = node_coordinates[temp_node][1] + return node_x, node_y + + +def produce_pattern_value(wn, all_node): + wn_o = copy.deepcopy(wn) + # 改_wz_____________________________ + # sample_node = wn_o.get_node(all_node[0]) + # num_categories = len(sample_node.demand_timeseries_list) + num_categories = 1 + columns = [f"D{i}" for i in range(num_categories)] + basic_demand_pd = pd.DataFrame(index=all_node, columns=columns) + for each in all_node: + node = wn_o.get_node(each) + for i in range(num_categories): + basic_demand_pd.loc[each, columns[i]] = node.demand_timeseries_list[ + i + ].base_value + + return basic_demand_pd + + +def _build_node_pipe_maps( + all_nodes, candidate_pipes, pipe_start_node, pipe_end_node, pipe_length +): + node_pipe_dic = {node: [] for node in all_nodes} + couple_node_length = {} + for pipe in candidate_pipes: + start_node = pipe_start_node[pipe] + end_node = pipe_end_node[pipe] + if start_node in node_pipe_dic: + node_pipe_dic[start_node].append(pipe) + if end_node in node_pipe_dic: + node_pipe_dic[end_node].append(pipe) + length = float(pipe_length[pipe]) + couple_node_length[f"{start_node},{end_node}"] = length + couple_node_length[f"{end_node},{start_node}"] = length + return node_pipe_dic, couple_node_length + + diff --git a/app/algorithms/burst_location/network_partitioner.py b/app/algorithms/burst_location/network_partitioner.py new file mode 100644 index 0000000..1a42ca5 --- /dev/null +++ b/app/algorithms/burst_location/network_partitioner.py @@ -0,0 +1,456 @@ +"""管网分区模块。""" + +import math + +import matplotlib.pyplot as plt +import networkx as nx +import networkx as networkx +import numpy as np +import pandas as pd +import pymetis +from scipy.sparse import coo_matrix, csr_matrix +from scipy.sparse.csgraph import connected_components + + +def _to_metis_edge_weight(edge_weight): + weight = float(edge_weight) + if not math.isfinite(weight): + raise ValueError(f"Invalid non-finite METIS edge weight: {edge_weight}") + # pymetis expects integer edge weights. + return max(1, int(round(weight))) + + +def _dedupe_preserve_order(items): + seen = set() + output = [] + for item in items: + if item in seen: + continue + seen.add(item) + output.append(item) + return output + + +def pick_center_pipe(node_x, node_y, candidate_pipe, pipe_start_node, pipe_end_node): + candidate_pipe_list = list(candidate_pipe) + start_nodes = pipe_start_node[candidate_pipe_list] + end_nodes = pipe_end_node[candidate_pipe_list] + + x_vals = (node_x[start_nodes].to_numpy() + node_x[end_nodes].to_numpy()) / 2.0 + y_vals = (node_y[start_nodes].to_numpy() + node_y[end_nodes].to_numpy()) / 2.0 + mean_x = float(np.mean(x_vals)) + mean_y = float(np.mean(y_vals)) + distance = np.abs(x_vals - mean_x) + np.abs(y_vals - mean_y) + center_idx = int(np.argmin(distance)) + return candidate_pipe_list[center_idx] + + +def pick_max_diameter_pipe(candidate_pipe, pipe_diameter): + candidate_pipe_list = list(candidate_pipe) + diameters = pd.to_numeric( + pipe_diameter.reindex(candidate_pipe_list), errors="coerce" + ).dropna() + if len(diameters) != len(candidate_pipe_list): + missing = sorted(set(candidate_pipe_list) - set(diameters.index)) + preview = ", ".join(map(str, missing[:10])) + raise ValueError(f"Missing or invalid diameter for pipes: {preview}") + + max_diameter = float(diameters.max()) + max_diameter_pipes = sorted( + [pipe for pipe, diameter in diameters.items() if float(diameter) == max_diameter], + key=str, + ) + return max_diameter_pipes[0] + + +def pick_dual_center_pipes( + node_x, node_y, candidate_pipe, pipe_start_node, pipe_end_node, pipe_diameter +): + geometric_center = pick_center_pipe( + node_x, node_y, candidate_pipe, pipe_start_node, pipe_end_node + ) + diameter_center = pick_max_diameter_pipe(candidate_pipe, pipe_diameter) + return _dedupe_preserve_order([geometric_center, diameter_center]) + + +def find_new_center_pipe( + node_x, + node_y, + candidate_pipe, + pipe_start_node, + pipe_end_node, + pipe_diameter, + record_center, +): + new_candidate_pipe = sorted(set(candidate_pipe) - set(record_center)) + if new_candidate_pipe == []: + new_candidate_pipe = candidate_pipe + center_t = pick_center_pipe( + node_x, + node_y, + new_candidate_pipe, + pipe_start_node, + pipe_end_node, + ) + return center_t + + +def cal_area_node_linked_pipe(nodeset, node_pipe_dic): + pipeset = [] + for temp_node in nodeset: + pipeset.extend(node_pipe_dic[temp_node]) + return pipeset + + +def metis_grouping_pipe_weight( + G0, + wn, + all_node_iter, + candidate_pipe_input, + group_num, + node_x, + node_y, + pipe_start_node_all, + pipe_end_node_all, + node_pipe_dic, + all_node_series, + couple_node_length, + pipe_diameter, +): + all_node_iter_series_new = all_node_series[all_node_iter] + all_node_iter_series_new = all_node_iter_series_new.sort_values(ascending=True) + all_node_iter_new = list(all_node_iter_series_new.index) + + G1 = G0.subgraph(all_node_iter_new) + delimiter = " " + adjacency_list = [] + node_dict = {} + c_new = 0 + for each_node in all_node_iter_new: + node_dict[each_node] = c_new + c_new = c_new + 1 + correspond_dic = {} + count_node = 0 + w = [] + for node_name in all_node_iter_new: + neighbors = G1[node_name] + w_temp = [] + n_t = [node_dict[node_name]] + for neighbor_name in sorted(neighbors.keys()): + edge_data = neighbors[neighbor_name] + edge_key = f"{node_name},{neighbor_name}" + reverse_edge_key = f"{neighbor_name},{node_name}" + if edge_key in couple_node_length: + edge_weight = couple_node_length[edge_key] + elif reverse_edge_key in couple_node_length: + edge_weight = couple_node_length[reverse_edge_key] + elif edge_data.get("weight") is not None: + edge_weight = float(edge_data["weight"]) + else: + # Ignore graph edges that are outside candidate pipes and have no usable + # partition weight (e.g. some non-pipe links in mixed network graphs). + continue + w_temp.append(_to_metis_edge_weight(edge_weight)) + n_t.append(node_dict[neighbor_name]) + w.append(w_temp) + correspond_dic[n_t[0]] = count_node + count_node = count_node + 1 + # del n_t[0] + adjacency_list.append(n_t) + adjacency_list_new = [[] * 1 for i in range(len(adjacency_list))] + w_new = [[] * 1 for i in range(len(adjacency_list))] + for i in range(len(adjacency_list)): + adjacency_list_new[int(adjacency_list[i][0])] = adjacency_list[i] + w_new[int(adjacency_list[i][0])] = w[i] + + for i in range(len(adjacency_list)): + del adjacency_list_new[i][0] + xadj = [0] + w_f = [] + final_adjacency_list = [] + for i in range(len(adjacency_list_new)): + final_adjacency_list = final_adjacency_list + adjacency_list_new[i] + xadj.append(len(final_adjacency_list)) + w_f = w_f + w_new[i] + + # (edgecuts, parts) = pymetis.part_graph(nparts=group_num, adjacency=adjacency_list_new) + metis_options = pymetis.Options() + metis_options.seed = 42 + (edgecuts, parts) = pymetis.part_graph( + nparts=group_num, + adjncy=final_adjacency_list, + xadj=xadj, + eweights=w_f, + options=metis_options, + ) + # (edgecuts, parts) = pymetis.part_graph(nparts=group_num, adjacency=adjacency_list_new) + candidate_group_list = [[] * 1 for i in range(group_num)] + for i in range(len(all_node_iter_new)): + candidate_group_list[parts[i]].append(all_node_iter_new[i]) + + """parts_new = np.zeros(len(candidate_node_input), dtype=int) + for i in range(len(candidate_group_list)): + temp_group = candidate_group_list[i] + for each_node in temp_group: + parts_new[node_dict[each_node]] = i + parts_new = list(parts_new)""" + + new_center = [] + new_group = [] + new_center_candidates = [] + new_all_node = [] + candidate_pipe_set = set(candidate_pipe_input) + all_grouped_pipe = [] + for i in range(group_num): + # 构建子图 + G_sub = G0.subgraph(candidate_group_list[i]) + + # 计算联通子图 + sub_graphs = networkx.connected_components(G_sub) + if networkx.number_connected_components(G_sub) == 1: + # 求交集 + nodeset = G_sub.nodes() + pipeset_set = set(cal_area_node_linked_pipe(nodeset, node_pipe_dic)) + candidate_pipe = sorted(pipeset_set.intersection(candidate_pipe_set)) + + # 判断集合是否保留 + if len(candidate_pipe) > 0: + # 保留 计算中心 + center_t = pick_center_pipe( + node_x, + node_y, + candidate_pipe, + pipe_start_node_all, + pipe_end_node_all, + ) + center_candidates_t = pick_dual_center_pipes( + node_x, + node_y, + candidate_pipe, + pipe_start_node_all, + pipe_end_node_all, + pipe_diameter, + ) + + # 更新 + new_center.append(center_t) + new_center_candidates.append(center_candidates_t) + new_group.append(candidate_pipe) + new_all_node.append(nodeset) + all_grouped_pipe = all_grouped_pipe + candidate_pipe + else: + for c in sorted(sub_graphs, key=lambda c: min(c)): + G_temp = G0.subgraph(c) + nodeset = G_temp.nodes() + pipeset = cal_area_node_linked_pipe(nodeset, node_pipe_dic) + pipeset_set = set(pipeset) + + # 求交集 + candidate_pipe = sorted(pipeset_set.intersection(candidate_pipe_set)) + # print(len(candidate_node)) + # 判断集合是否保留 + if len(candidate_pipe) > 0: + # 保留 计算中心 + center_t = pick_center_pipe( + node_x, + node_y, + candidate_pipe, + pipe_start_node_all, + pipe_end_node_all, + ) + center_candidates_t = pick_dual_center_pipes( + node_x, + node_y, + candidate_pipe, + pipe_start_node_all, + pipe_end_node_all, + pipe_diameter, + ) + # 更新 + new_center.append(center_t) + new_center_candidates.append(center_candidates_t) + new_group.append(candidate_pipe) + new_all_node.append(nodeset) + all_grouped_pipe = all_grouped_pipe + candidate_pipe + record_center = [] + c_g = 0 + for each_group in new_group: + if len(each_group) < 3: + record_center.append(new_center[c_g]) + c_g += 1 + c_g = 0 + for each_group in new_group: + if len(each_group) >= 3: + if new_center[c_g] in record_center: + new_center[c_g] = find_new_center_pipe( + node_x, + node_y, + each_group, + pipe_start_node_all, + pipe_end_node_all, + pipe_diameter, + record_center, + ) + new_center_candidates[c_g] = _dedupe_preserve_order( + [new_center[c_g]] + list(new_center_candidates[c_g]) + ) + record_center.append(new_center[c_g]) + c_g += 1 + + # visualize_metis_partition( + # G0, new_center, new_group, + # node_x, node_y, + # pipe_start_node_all, pipe_end_node_all + # ) + return new_center, new_group, new_all_node, new_center_candidates + + +def visualize_metis_partition( + G, + center_pipes, + pipe_groups, + node_x, + node_y, + pipe_start_node_all, + pipe_end_node_all, + title: str | None = None, + block: bool = True, + pause_seconds: float | None = None, +): + """ + 可视化METIS分区结果(单图模式) + 参数: + G: 原始管网图(nx.Graph) + center_pipes: 中心管道列表(list) + pipe_groups: 分组管道列表(list of lists) + node_x: 节点X坐标字典(dict) + node_y: 节点Y坐标字典(dict) + pipe_start_node_all: 管道起点字典(dict) + pipe_end_node_all: 管道终点字典(dict) + """ + fig = plt.figure("metis_partition_convergence", figsize=(22.51, 12.48)) + fig.clf() + ax = fig.add_subplot(111) + if not block: + plt.ion() + + # 生成颜色映射(自动扩展颜色数量) + colors = plt.cm.tab20(np.linspace(0, 1, len(pipe_groups))) + + # --- 绘制背景管网(灰色半透明) --- + for edge in G.edges(): + start_node, end_node = edge + ax.plot( + [node_x[start_node], node_x[end_node]], + [node_y[start_node], node_y[end_node]], + color="lightgray", + linewidth=0.5, + alpha=0.3, + zorder=1, # 确保背景在底层 + ) + + # --- 绘制各分区管道(彩色)--- + legend_handles = [] # 用于图例的句柄 + for i, (group, center) in enumerate(zip(pipe_groups, center_pipes)): + color = colors[i % len(colors)] # 循环使用颜色 + + # 绘制分组管道 + for pipe in group: + start = pipe_start_node_all[pipe] + end = pipe_end_node_all[pipe] + line = ax.plot( + [node_x[start], node_x[end]], + [node_y[start], node_y[end]], + color=color, + linewidth=2.5, + alpha=0.8, + zorder=2, + ) + # 只为每个分组的第一个管道添加图例句柄 + if pipe == group[0]: + legend_handles.append(line[0]) + + # 高亮中心管道(红色虚线) + if center in pipe_start_node_all and center in pipe_end_node_all: + start = pipe_start_node_all[center] + end = pipe_end_node_all[center] + ax.plot( + [node_x[start], node_x[end]], + [node_y[start], node_y[end]], + color="red", + linewidth=4, + linestyle="--", + dash_capstyle="round", + zorder=3, # 确保中心管道在最顶层 + ) + + # --- 添加图例和标注 --- + # 分组图例 + if legend_handles: + group_labels = [f"Group {i + 1}" for i in range(len(pipe_groups))] + ax.legend( + legend_handles, + group_labels, + loc="upper right", + title="Partitions", + fontsize=8, + title_fontsize=10, + ) + + # 中心管道标注(可选) + for i, center in enumerate(center_pipes): + if center in pipe_start_node_all: + x = ( + node_x[pipe_start_node_all[center]] + node_x[pipe_end_node_all[center]] + ) / 2 + y = ( + node_y[pipe_start_node_all[center]] + node_y[pipe_end_node_all[center]] + ) / 2 + ax.text( + x, + y, + f"C{i + 1}", + color="red", + fontsize=10, + ha="center", + va="center", + bbox=dict(facecolor="white", alpha=0.8, edgecolor="none"), + ) + + # --- 图形美化 --- + ax.set_title(title or "Water Network Partitioning Overview", fontsize=14, pad=20) + ax.set_xlabel("X Coordinate", fontsize=10) + ax.set_ylabel("Y Coordinate", fontsize=10) + ax.grid(True, alpha=0.2, linestyle=":") + fig.tight_layout() + + # 显示图形并强制刷新,避免迭代显示滞后一轮。 + plt.show(block=block) + if not block: + fig.canvas.draw_idle() + fig.canvas.flush_events() + pause_value = 0.001 if pause_seconds is None else max(0.0, float(pause_seconds)) + plt.pause(max(0.001, pause_value)) + elif pause_seconds is not None: + plt.pause(max(0.0, float(pause_seconds))) + return fig + + +def generate_adjlist_with_all_edges(G, delimiter): + for s, nbrs in G.adjacency(): + line = str(s) + delimiter + for t, data in nbrs.items(): + line += str(t) + delimiter + yield line[: -len(delimiter)] + + +def cal_group_num(candidate_node_input, cal_group_num): + candidate_node_num = len(candidate_node_input) + if candidate_node_num > 100: + group_num_input = cal_group_num # 30 + else: + group_num_input = 10 + + return group_num_input + + diff --git a/app/algorithms/burst_location/noise_generator.py b/app/algorithms/burst_location/noise_generator.py new file mode 100644 index 0000000..cef6d27 --- /dev/null +++ b/app/algorithms/burst_location/noise_generator.py @@ -0,0 +1,198 @@ +"""噪声生成模块。""" + +import copy +import random + +import numpy as np +import pandas as pd + +from .leak_simulator import simple_add_leak, simple_recover_wn, simple_simulation_pf + + +def add_noise_pd(data, noise_type, noise_para): + output_data = copy.deepcopy(data) + if type(output_data) == pd.core.frame.Series: + if noise_type == "uni": + for x in output_data.index: + noise = (np.random.random() - 0.5) * 2 + output_data[x] = output_data[x] + noise * noise_para + + elif noise_type == "gauss": + noise = np.random.normal(loc=0, scale=noise_para, size=output_data.shape) + output_data = output_data + noise + elif type(output_data) == pd.core.frame.DataFrame: + if noise_type == "uni": + noise = (np.random.random(size=output_data.shape) - 0.5) * 2 + output_data = output_data + noise * noise_para + + elif noise_type == "gauss": + noise = np.random.normal(loc=0, scale=noise_para, size=output_data.shape) + output_data = output_data + noise + return output_data + + +def add_noise_number(data, noise_type, noise_para): + output_data = copy.deepcopy(data) + if noise_type == "uni": + noise = (np.random.random() - 0.5) * 2 + output_data = output_data + noise * noise_para + + elif noise_type == "gauss": + noise = random.gauss(0, noise_para) + output_data = output_data + noise + return output_data + + +def add_noise_number_flow(data, noise_para_mean, noise_para_std1, noise_para_std2): + output_data = copy.deepcopy(data) + noise_flag1 = np.random.random() - 0.5 + if noise_flag1 < 0: + noise = noise_para_mean - abs(np.random.normal(loc=0, scale=noise_para_std1)) + else: + noise = noise_para_mean + abs(np.random.normal(loc=0, scale=noise_para_std2)) + noise_flag2 = np.random.random() - 0.5 + if noise_flag2 < 0: + noise_f = noise * (-1) + else: + noise_f = noise + output_data = output_data + noise_f + return output_data + + +def produce_noise_number(noise_type, noise_para): + if noise_type == "uni": + noise = (np.random.random() - 0.5) * 2 + noise = noise * noise_para + elif noise_type == "gauss": + noise = random.gauss(0, noise_para) + else: + noise = 0 + return noise + + +def add_noise_percentage_pd(data, noise_type, noise_para): + output_data = copy.deepcopy(data) + + if type(output_data) == pd.core.frame.Series: + if noise_type == "uni": + for x in output_data.index: + noise = (np.random.random() - 0.5) * 2 + output_data[x] = output_data[x] * (1 + noise * noise_para / 100) + + elif noise_type == "gauss": + for x in output_data.index: + noise = np.random.gauss(0, noise_para) + output_data[x] = output_data[x] * (1 + noise / 100) + # std_noise = noise.std() + elif type(output_data) == pd.core.frame.DataFrame: + if noise_type == "uni": + noise = (np.random.random(size=output_data.shape) - 0.5) * 2 + output_data = output_data * (1 + noise * noise_para / 100) + + elif noise_type == "gauss": + noise = np.random.normal(loc=0, scale=noise_para, size=output_data.shape) + output_data = output_data * (1 + noise / 100) + # std_noise = noise.std().mean() + return output_data + + +def add_noise_in_wn_pf( + wn, + pipe_c_noise, + timestep_list, + pipe_coefficient, + sensor_name, + sensor_f_name, + all_node, + basic_demand_pd, + noise_type, + noise_para, + leak_pipe, + leak_flow, +): + + wn.options.time.duration = 0 + pipe_roughness_change = add_noise_pd(pipe_coefficient, noise_type, pipe_c_noise) + wn = change_para_of_wn(wn, pipe_roughness_change) + record_pressure = pd.DataFrame(index=timestep_list, columns=sensor_name) + record_flow = pd.DataFrame(index=timestep_list, columns=sensor_f_name) + record_noise_all = pd.DataFrame( + index=pd.MultiIndex.from_product([timestep_list, all_node]), + columns=basic_demand_pd.columns, + ) + record_noise_all = record_noise_all.sort_index() + + # normal 获取添加噪声后的监测点数据 + for i in range(len(timestep_list)): + wn, record_noise = change_node_demand( + wn, basic_demand_pd, all_node, noise_type, noise_para + ) + record_noise_all.loc[timestep_list[i]].loc[:, :] = record_noise + pressure_temp, flow_temp = simple_simulation_pf( + wn, sensor_name, sensor_f_name, [], [] + ) + record_pressure.iloc[i, :] = pressure_temp + record_flow.iloc[i, :] = flow_temp + + # leak_simulation 获取添加漏损后的监测点数据 + record_pressure_leak = pd.DataFrame(index=timestep_list, columns=sensor_name) + record_flow_leak = pd.DataFrame(index=timestep_list, columns=sensor_f_name) + # 改_wz_________________________________________ + # add leak + wn, whole_inf, add_pipe1 = simple_add_leak(wn, leak_flow, leak_pipe) + # simulation + for i in range(len(timestep_list)): + record_noise = record_noise_all.loc[timestep_list[i]] + wn = change_node_demand_leak(wn, record_noise, all_node) + pressure_temp, flow_temp = simple_simulation_pf( + wn, sensor_name, sensor_f_name, leak_pipe, add_pipe1 + ) + record_pressure_leak.iloc[i, :] = pressure_temp + record_flow_leak.iloc[i, :] = flow_temp + # delete leak + wn = simple_recover_wn(wn, whole_inf) + return wn, record_pressure, record_flow, record_pressure_leak, record_flow_leak + + +def change_node_demand(wn, basic_demand_pd, all_node, noise_type, noise_para): + # 改_wz_____________________________________ + record_noise = pd.DataFrame(index=all_node, columns=basic_demand_pd.columns) + for each_node in all_node: + node = wn.get_node(each_node) + num_columns = len(basic_demand_pd.columns) + # 处理前N-1列(如果有) + for i in range(num_columns - 1): + # 获取原始值并添加噪声 + record_noise.loc[each_node].iloc[i] = ( + 1 + produce_noise_number(noise_type, noise_para) + ) * basic_demand_pd.loc[each_node].iloc[i] + node.demand_timeseries_list[i].base_value = record_noise.loc[ + each_node + ].iloc[i] + # 处理最后一列(当列数>=1时) + if num_columns >= 1: + last_col = basic_demand_pd.columns[-1] + original_last = basic_demand_pd.loc[each_node, last_col] + record_noise.loc[each_node, last_col] = original_last + node.demand_timeseries_list[-1].base_value = original_last + + return wn, record_noise + + +def change_node_demand_leak(wn, record_noise, all_node): + sample_node = wn.get_node(all_node[0]) + # num_categories = len(sample_node.demand_timeseries_list) + num_categories = 1 + for each in all_node: + node = wn.get_node(each) + for i in range(num_categories): + node.demand_timeseries_list[i].base_value = record_noise.loc[each].iloc[i] + return wn + + +def change_para_of_wn(wn, pipe_roughness_change): + for pipe_name, pipe in wn.pipes(): + pipe.roughness = pipe_roughness_change[pipe_name] + return wn + + diff --git a/app/algorithms/burst_location/similarity_calculator.py b/app/algorithms/burst_location/similarity_calculator.py new file mode 100644 index 0000000..7fecaf8 --- /dev/null +++ b/app/algorithms/burst_location/similarity_calculator.py @@ -0,0 +1,858 @@ +"""相似性计算模块。""" + +import math + +import numpy as np +import pandas as pd + + +def cal_similarity_simple_return_dd( + similarity_mode, + monitor_p, + predict_p, + normal_p, + leak_p, + monitor_p_all, + predict_p_all, + normal_p_all, + leak_p_all, + important_sensor, + mean_dpressure, + dpressure_std, + dpressure_std_all, + if_gy=0, + cos_or_flow=1, +): + # cos_or_flow 用于 CAF + dpressure_s = normal_p - leak_p + dpressure = predict_p - monitor_p + act_dpressure = pd.Series(dtype=object) + for i in range(len(leak_p.index)): + if dpressure_std.iloc[i] > -200: # 0.001: + if if_gy == 1: + act_dpressure[leak_p.index[i]] = ( + leak_p.iloc[i] - monitor_p.iloc[i] + ) / dpressure_std.iloc[i] + else: + act_dpressure[leak_p.index[i]] = leak_p.iloc[i] - monitor_p.iloc[i] + + if similarity_mode == "COS" or (similarity_mode == "CAF" and cos_or_flow == 1): + + """if leak_p.min()<0: + none_flag = 1 + similarity_cos = 0 + similarity_dis = 0 + else:""" + none_flag = 0 + sensor_for_cos = sorted( + set(dpressure_s.index).intersection(set(act_dpressure.index)) + ) + """if len(dpressure_s) ==0 or len(dpressure) ==0: + jj=9 + else:""" + try: + s1 = np.dot( + np.transpose(dpressure_s.loc[sensor_for_cos]), + dpressure.loc[sensor_for_cos], + ) + s2 = np.linalg.norm(dpressure_s.loc[sensor_for_cos]) * np.linalg.norm( + dpressure.loc[sensor_for_cos] + ) + if s2 == 0: + s2 = s2 + 0.0001 + similarity_cos = s1 / s2 + similarity_dis = 0 + except Exception as e: + print(dpressure_s) + print(sensor_for_cos) + print(act_dpressure) + print(dpressure_std) + print(dpressure) + + elif similarity_mode == "DIS" or (similarity_mode == "CAF" and cos_or_flow == 2): + """if leak_p.min()<0: + none_flag = 1 + else:""" + none_flag = 0 + important_sensor = sorted( + set(important_sensor).intersection(set(act_dpressure.index)) + ) + part_dpressure = dpressure_s[important_sensor] - dpressure[important_sensor] + similarity_pre_DIS = np.linalg.norm(part_dpressure) + # similarity_pre_DIS_later = 1 / (1 + similarity_pre_DIS) + similarity_dis = similarity_pre_DIS + similarity_cos = 0 + + elif similarity_mode == "CAD_new": + act_dpressure = leak_p - monitor_p + """if leak_p.min() < 0: + none_flag = 1 + similarity_cos = 0 + similarity_dis =0 + else:""" + none_flag = 0 + # cos + s1 = np.dot(np.transpose(dpressure_s), dpressure) + s2 = np.linalg.norm(dpressure_s) * np.linalg.norm(dpressure) + + if s2 == 0: + s2 = s2 + 0.0001 + similarity_cos = s1 / s2 + + # DIS + part_dpressure = act_dpressure.loc[important_sensor] + similarity_pre_DIS = np.linalg.norm(part_dpressure) + similarity_pre_DIS_later = 1 / (1 + similarity_pre_DIS) + similarity_dis = similarity_pre_DIS + + elif similarity_mode == "CAD_new_gy" or similarity_mode == "CDF": + # cos + sensor_for_cos = sorted( + set(dpressure_s.index).intersection(set(act_dpressure.index)) + ) + if len(sensor_for_cos) == 0 and len(dpressure_s) == 0: + similarity_cos = 0 + elif len(sensor_for_cos) == 0 and len(dpressure_s) > 0: + sensor_for_cos = list(dpressure_s.index) + none_flag = 0 + s1 = np.dot( + np.transpose(dpressure_s.loc[sensor_for_cos]), + dpressure.loc[sensor_for_cos], + ) + s2 = np.linalg.norm(dpressure_s.loc[sensor_for_cos]) * np.linalg.norm( + dpressure.loc[sensor_for_cos] + ) + + if s2 == 0: + s2 = s2 + 0.0001 + similarity_cos = s1 / s2 + else: + none_flag = 0 + s1 = np.dot( + np.transpose(dpressure_s.loc[sensor_for_cos]), + dpressure.loc[sensor_for_cos], + ) + s2 = np.linalg.norm(dpressure_s.loc[sensor_for_cos]) * np.linalg.norm( + dpressure.loc[sensor_for_cos] + ) + + if s2 == 0: + s2 = s2 + 0.0001 + similarity_cos = s1 / s2 + + # DIS + important_sensor_new = sorted( + set(important_sensor).intersection(set(act_dpressure.index)) + ) + if len(important_sensor_new) == 0: + important_sensor_new = important_sensor + act_dpressure = pd.Series(dtype=object) + for i in range(len(leak_p_all.index)): + # if dpressure_std.iloc [i] > -200: # 0.001: + if if_gy == 1: + act_dpressure[leak_p_all.index[i]] = ( + leak_p_all.iloc[i] - monitor_p_all.iloc[i] + ) / dpressure_std_all.iloc[i] + else: + act_dpressure[leak_p_all.index[i]] = ( + leak_p_all.iloc[i] - monitor_p_all.iloc[i] + ) + # part_dpressure = act_dpressure.loc[important_sensor_new] + + part_dpressure = ( + dpressure.loc[important_sensor_new] - dpressure_s.loc[important_sensor_new] + ) + similarity_pre_DIS = np.linalg.norm(part_dpressure) ## chang test + # part_dpressure = dpressure_s.loc[important_sensor]-dpressure.loc[important_sensor] + # similarity_pre_DIS = np.linalg.norm(part_dpressure) + # similarity_pre_DIS_later = 1 / (1 + similarity_pre_DIS) + similarity_dis = similarity_pre_DIS + elif similarity_mode == "OF": + # cos + similarity_cos = 0 + none_flag = 0 + # DIS + important_sensor_new = sorted( + set(important_sensor).intersection(set(act_dpressure.index)) + ) + if len(important_sensor_new) == 0: + important_sensor_new = important_sensor + act_dpressure = pd.Series(dtype=object) + for i in range(len(leak_p_all.index)): + # if dpressure_std.iloc [i] > -200: # 0.001: + if if_gy == 1: + act_dpressure[leak_p_all.index[i]] = ( + leak_p_all.iloc[i] - monitor_p_all.iloc[i] + ) / dpressure_std_all.iloc[i] + else: + act_dpressure[leak_p_all.index[i]] = ( + leak_p_all.iloc[i] - monitor_p_all.iloc[i] + ) + # part_dpressure = act_dpressure.loc[important_sensor_new] + + part_dpressure = ( + dpressure.loc[important_sensor_new] - dpressure_s.loc[important_sensor_new] + ) + similarity_pre_DIS = np.linalg.norm(part_dpressure) ## chang test + # part_dpressure = dpressure_s.loc[important_sensor]-dpressure.loc[important_sensor] + # similarity_pre_DIS = np.linalg.norm(part_dpressure) + # similarity_pre_DIS_later = 1 / (1 + similarity_pre_DIS) + similarity_dis = similarity_pre_DIS + + return similarity_cos, similarity_dis, none_flag + + +def adjust( + similarity_cos, + similarity_dis, + record_success_candidate, + record_success_no_candidate, +): + if len(record_success_no_candidate) > 0: + for each in record_success_no_candidate: + similarity_cos[each] = similarity_cos[record_success_candidate].min() * 0.9 + similarity_dis[each] = similarity_dis[record_success_candidate].max() * 1.1 + return similarity_cos, similarity_dis + + +def cal_sq_all_multi( + similarity_cos, + similarity_dis, + similarity_f, + candidate_pipe, + timestep_list_spc, + if_flow, + if_only_cos, + if_only_flow, + cos_h_input, + dis_h_input, + dis_f_h_input, + if_compalsive, + cos_sensor_num, + flow_sensor_num, +): + """融合多种相似性并输出按时刻与候选管段组织的综合相似度。 + + 该函数会根据模式开关(是否仅流量、是否仅 COS、是否包含流量)对 + `similarity_cos`、`similarity_dis`、`similarity_f` 做标准化,并计算 + 权重 `sq_cos/sq_dis/sq_f` 后进行加权融合。 + + Args: + similarity_cos: 压力余弦相似性(DataFrame/Series,通常为时刻 x 候选管段)。 + similarity_dis: 压力距离相似性(DataFrame/Series,通常为时刻 x 候选管段)。 + similarity_f: 流量距离相似性(DataFrame/Series,通常为时刻 x 候选管段)。 + candidate_pipe: 候选管段列表,用于输出列索引。 + timestep_list_spc: 时刻列表,用于输出行索引。 + if_flow: 是否启用流量相似性(1 启用,0 禁用)。 + if_only_cos: 相似性模式标识(0: COS+DIS;1: COS;其他值按分支定义处理)。 + if_only_flow: 是否仅使用流量相似性(1 是,0 否)。 + cos_h_input: 外部给定的 COS 权重(强制权重模式下使用)。 + dis_h_input: 外部给定的 DIS 权重(强制权重模式下使用)。 + dis_f_h_input: 外部给定的流量权重(强制权重模式下使用)。 + if_compalsive: 是否使用外部强制权重(1 使用输入权重,0 自动计算权重)。 + cos_sensor_num: 压力传感器数量,用于权重调整。 + flow_sensor_num: 流量传感器数量,用于权重调整。 + + Returns: + tuple[pd.DataFrame | pd.Series, float, float, float]: + - output_similarity_pd: 综合相似性结果。 + - sq_cos: 最终 COS 权重。 + - sq_dis: 最终 DIS 权重。 + - sq_f: 最终流量权重。 + """ + if if_only_flow == 1: + similarity_f, h_f = cal_sq_single_array( + similarity_f.values.reshape((-1, 1)), if_direct=2 + ) + sq_cos = 0 + sq_dis = 0 + sq_f = 1 + similarity_all = similarity_f * sq_f + output_similarity = similarity_all.reshape((-1, len(candidate_pipe))) + output_similarity_pd = pd.DataFrame( + output_similarity, index=timestep_list_spc, columns=candidate_pipe + ) + else: + if if_only_cos == 0: + if if_flow == 1: + # standerdize + similarity_cos, h_cos = cal_sq_single_array( + similarity_cos.values.reshape((-1, 1)), if_direct=1 + ) + similarity_dis, h_dis = cal_sq_single_array( + similarity_dis.values.reshape((-1, 1)), if_direct=2 + ) + similarity_f, h_f = cal_sq_single_array( + similarity_f.values.reshape((-1, 1)), if_direct=2 + ) + if if_compalsive == 1: + sq_cos = cos_h_input + sq_dis = dis_h_input + sq_f = dis_f_h_input + else: + """sq_cos = h_cos/(h_cos +h_dis +h_f ) + sq_dis = h_dis/(h_cos +h_dis +h_f ) + sq_f = h_f/(h_cos +h_dis +h_f )""" + sq_cos, sq_dis, sq_f = add_weight_for_SQ( + h_cos, h_dis, h_f, cos_sensor_num, flow_sensor_num + ) + + """if cos_sensor_num == 2 and sq_cos>0.2: + sq_cos = 0.2 + sq_dis = 0.8*h_dis / (h_dis + h_f) + sq_f = 0.8*h_f / (h_dis + h_f) + if cos_sensor_num == 1 and sq_dis > 0.3: + sq_cos = 0.1 + sq_dis = 0.3 + sq_f = 0.6""" + sq_cos, sq_dis, sq_f = adjust_ratio("CDF", sq_cos, sq_dis, sq_f) + if cos_sensor_num <= 1: + sq_cos = 0 + # similarity + + similarity_all = ( + similarity_cos * sq_cos + + similarity_dis * sq_dis + + similarity_f * sq_f + ) + output_similarity = similarity_all.reshape((-1, len(candidate_pipe))) + output_similarity_pd = pd.DataFrame( + output_similarity, index=timestep_list_spc, columns=candidate_pipe + ) + else: + # standerdize + similarity_cos, h_cos = cal_sq_single_array( + similarity_cos.values.reshape((-1, 1)), if_direct=1 + ) + similarity_dis, h_dis = cal_sq_single_array( + similarity_dis.values.reshape((-1, 1)), if_direct=2 + ) + if if_compalsive == 1: + sq_cos = cos_h_input + sq_dis = dis_h_input + else: + sq_cos = h_cos / (h_cos + h_dis) + sq_dis = h_dis / (h_cos + h_dis) + if cos_sensor_num == 2 and sq_cos > 0.5: + sq_cos = 0.5 + sq_dis = 0.5 + sq_cos, sq_dis, sq_f = adjust_ratio("CAD_new_gy", sq_cos, sq_dis, 0) + sq_f = 0 + # similarity + similarity_all = similarity_cos * sq_cos + similarity_dis * sq_dis + output_similarity = similarity_all.reshape((-1, len(candidate_pipe))) + output_similarity_pd = pd.DataFrame( + output_similarity, index=timestep_list_spc, columns=candidate_pipe + ) + elif if_only_cos == 1: + if if_flow == 1: + # standerdize + similarity_cos, h_cos = cal_sq_single_array( + similarity_cos.values.reshape((-1, 1)), if_direct=1 + ) + similarity_f, h_f = cal_sq_single_array( + similarity_f.values.reshape((-1, 1)), if_direct=2 + ) + if if_compalsive == 1: + sq_cos = cos_h_input + sq_f = dis_f_h_input + else: + sq_cos = h_cos / (h_cos + h_f) + sq_f = h_f / (h_cos + h_f) + sq_cos, sq_dis, sq_f = adjust_ratio("CAF", sq_cos, 0, sq_f) + sq_dis = 0 + # similarity + similarity_all = similarity_cos * sq_cos + similarity_f * sq_f + output_similarity = similarity_all.reshape((-1, len(candidate_pipe))) + output_similarity_pd = pd.DataFrame( + output_similarity, index=timestep_list_spc, columns=candidate_pipe + ) + + else: + sq_cos = cos_h_input + sq_dis = dis_h_input + sq_f = dis_f_h_input + output_similarity_pd = similarity_cos + else: + sq_cos = cos_h_input + sq_dis = dis_h_input + sq_f = dis_f_h_input + output_similarity_pd = 1 / (similarity_dis + 1) + return output_similarity_pd, sq_cos, sq_dis, sq_f + + +def add_weight_for_SQ(h_cos, h_dis, h_f, sensor_cos_num, sensor_f_num): + h_f_new = h_f * sensor_f_num + if sensor_cos_num <= 1: + h_cos_new = 0 + h_dis_new = h_dis * sensor_cos_num + else: + h_cos_new = h_cos * sensor_cos_num # / 2 + h_dis_new = h_dis * sensor_cos_num # / 2 + cos_sq = h_cos_new / (h_cos_new + h_dis_new + h_f_new) + dis_sq = h_dis_new / (h_cos_new + h_dis_new + h_f_new) + f_sq = h_f_new / (h_cos_new + h_dis_new + h_f_new) + + if sensor_cos_num == 2 and cos_sq > 0.2: + cos_sq = 0.2 + dis_sq = 0.8 * h_dis_new / (h_dis_new + h_f_new) + f_sq = 0.8 * h_f_new / (h_dis_new + h_f_new) + """if sensor_cos_num == 1: + if dis_sq / f_sq > sensor_cos_num/sensor_f_num: + dis_sq = sensor_cos_num/sensor_f_num + f_sq=1-dis_sq""" + # if h_dis_new/h_f_new > sensor_cos_num/sensor_f_num + return cos_sq, dis_sq, f_sq + + +def cal_sq_single_array(similarity_pre, if_direct): + if similarity_pre.max() - similarity_pre.min() == 0: + similarity_pre = np.ones(similarity_pre.shape) + else: + if if_direct == 1: + similarity_pre = ( + 0.998 + * (similarity_pre - similarity_pre.min()) + / (similarity_pre.max() - similarity_pre.min()) + + 0.002 + ) + else: + similarity_pre = ( + 0.998 + * (similarity_pre.max() - similarity_pre) + / (similarity_pre.max() - similarity_pre.min()) + + 0.002 + ) + # calculate pij + similarity_p = similarity_pre / similarity_pre.sum() + # cal xinxishang + similarity_lnp = np.zeros((len(similarity_pre), 1)) + for j in range(len(similarity_p)): + similarity_lnp[j] = -similarity_p[j] * math.log(similarity_p[j], math.e) + h = 1 - 1 / math.log(len(similarity_pre), math.e) * similarity_lnp.sum() + return similarity_pre, h + + +def cal_similarity_all_multi_new_sq_improve_double_lzr( + candidate_pipe, + similarity_mode, + pressure_leak, + monitor_p, + predict_p, + normal_p, + if_flow, + if_only_cos, + if_only_flow, + flow_leak, + monitor_f, + predict_f, + normal_f, + timestep_list, + Top_sensor_num, + if_gy, + effective_sensor, + cos_h, + dis_h, + dis_f_h, + if_compalsive, + max_flow, +): + similarity = pd.Series(dtype=float, index=candidate_pipe) + similarity_detail: pd.DataFrame | None = None + important_p_sensor = cal_top_sensors(monitor_p, predict_p, Top_sensor_num) + # important_f_sensor, basic_f = cal_top_f_sensor(normal_f) + important_f_sensor = monitor_f.columns + if ( + len(important_p_sensor) > 0 or len(important_f_sensor) > 0 + ): # if len(important_p_sensor) > 0 + break_flag = 0 + pressure_leak_new = pressure_leak.swaplevel() + # flow_leak_new = flow_leak.swaplevel() + if isinstance(flow_leak, pd.DataFrame) and len(flow_leak) > 0: + flow_leak_new = flow_leak.swaplevel() + else: + flow_leak_new = None + total_similarity_cos = pd.DataFrame(index=timestep_list, columns=candidate_pipe) + total_similarity_dis = pd.DataFrame(index=timestep_list, columns=candidate_pipe) + total_similarity_dis_f = pd.DataFrame( + index=timestep_list, columns=candidate_pipe + ) + + for timestep in timestep_list: + # cal p_cos, p_dis, f_dis + if if_only_flow != 1: + pressure_leak_temp = pressure_leak_new.loc[timestep].loc[ + :, effective_sensor + ] + monitor_p_temp = monitor_p.loc[timestep, effective_sensor] + predict_p_temp = predict_p.loc[timestep, effective_sensor] + normal_p_temp = normal_p.loc[timestep, effective_sensor] + + ( + total_similarity_cos.loc[timestep, :], + total_similarity_dis.loc[timestep, :], + ) = cal_similarity_all_cos_dis( + candidate_pipe, + pressure_leak_temp, + similarity_mode, + monitor_p_temp, + predict_p_temp, + normal_p_temp, + pressure_leak_new.loc[timestep].loc[:, monitor_p.columns], + monitor_p.loc[timestep, :], + predict_p.loc[timestep, :], + normal_p.loc[timestep, :], + important_p_sensor, + if_gy, + cos_or_flow=1, + ) + + if if_flow == 1: + if len(timestep_list) == 1: + leak_f_temp = flow_leak_new.loc[timestep].loc[:, important_f_sensor] + monitor_f_temp = monitor_f.loc[timestep, important_f_sensor] + predict_f_temp = predict_f.loc[timestep, important_f_sensor] + normal_f_temp = normal_f.loc[timestep, important_f_sensor] + basic_normal_f_temp = abs(max_flow.loc[important_f_sensor]) + + leak_f_temp = leak_f_temp / basic_normal_f_temp + monitor_f_temp = monitor_f_temp / basic_normal_f_temp + predict_f_temp = predict_f_temp / basic_normal_f_temp + normal_f_temp = normal_f_temp / basic_normal_f_temp + + else: + basic_f = abs(max_flow.loc[important_f_sensor]) + leak_f_temp = ( + flow_leak_new.loc[timestep].loc[:, important_f_sensor] / basic_f + ) + monitor_f_temp = ( + monitor_f.loc[timestep, important_f_sensor] / basic_f + ) + predict_f_temp = ( + predict_f.loc[timestep, important_f_sensor] / basic_f + ) + normal_f_temp = normal_f.loc[timestep, important_f_sensor] / basic_f + _, total_similarity_dis_f.loc[timestep, :] = cal_similarity_all_cos_dis( + candidate_pipe, + leak_f_temp, + similarity_mode, + monitor_f_temp, + predict_f_temp, + normal_f_temp, + flow_leak_new.loc[timestep].loc[:, monitor_f.columns], + monitor_f.loc[timestep, :], + predict_f.loc[timestep, :], + normal_f.loc[timestep, :], + important_f_sensor, + if_gy, + cos_or_flow=2, + ) + else: + total_similarity_dis_f = [] + similarity_all, cos_h, dis_h, dis_f_h = cal_sq_all_multi( + total_similarity_cos, + total_similarity_dis, + total_similarity_dis_f, + candidate_pipe, + timestep_list, + if_flow, + if_only_cos, + if_only_flow, + cos_h, + dis_h, + dis_f_h, + if_compalsive, + len(important_p_sensor), + len(important_f_sensor), + ) + if len(timestep_list) == 1: + similarity = similarity_all.iloc[0] + elif len(timestep_list) > 3: + for each_candidate in candidate_pipe: + similarity[each_candidate] = remove_3_sigma( + similarity_all.loc[:, each_candidate] + ) + else: + for each_candidate in candidate_pipe: + similarity[each_candidate] = similarity_all.loc[ + :, each_candidate + ].mean() + similarity = similarity.sort_values(ascending=False, kind="mergesort") + detail_index = [str(pipe) for pipe in candidate_pipe] + similarity_detail = pd.DataFrame(index=detail_index) + similarity_detail.index.name = "pipe_id" + if isinstance(total_similarity_cos, pd.DataFrame) and len(total_similarity_cos) > 0: + pressure_cos_mean = ( + total_similarity_cos.mean(axis=0) + .reindex(candidate_pipe) + .to_numpy(dtype=float) + ) + else: + pressure_cos_mean = np.full(len(candidate_pipe), np.nan) + if isinstance(total_similarity_dis, pd.DataFrame) and len(total_similarity_dis) > 0: + pressure_dis_mean = ( + total_similarity_dis.mean(axis=0) + .reindex(candidate_pipe) + .to_numpy(dtype=float) + ) + else: + pressure_dis_mean = np.full(len(candidate_pipe), np.nan) + if isinstance(total_similarity_dis_f, pd.DataFrame) and len(total_similarity_dis_f) > 0: + flow_dis_mean = ( + total_similarity_dis_f.mean(axis=0) + .reindex(candidate_pipe) + .to_numpy(dtype=float) + ) + else: + flow_dis_mean = np.full(len(candidate_pipe), np.nan) + similarity_detail["pressure_cos_mean"] = pressure_cos_mean + similarity_detail["pressure_dis_mean"] = pressure_dis_mean + similarity_detail["flow_dis_mean"] = flow_dis_mean + similarity_detail["weight_cos"] = float(cos_h) + similarity_detail["weight_dis"] = float(dis_h) + similarity_detail["weight_flow"] = float(dis_f_h) + similarity_detail["final_similarity"] = ( + similarity.reindex(candidate_pipe).to_numpy(dtype=float) + ) + similarity_detail["similarity_rank"] = ( + similarity_detail["final_similarity"].rank(method="dense", ascending=False) + ).astype(int) + similarity_detail["pressure_sensor_count"] = int(len(important_p_sensor)) + similarity_detail["flow_sensor_count"] = int(len(important_f_sensor)) + similarity_detail = similarity_detail.sort_values( + by="final_similarity", ascending=False, kind="mergesort" + ) + else: + break_flag = 1 + similarity = 0 + cos_h = 0 + dis_h = 0 + dis_f_h = 0 + return similarity, cos_h, dis_h, dis_f_h, break_flag, similarity_detail + + +def cal_similarity_all_cos_dis( + candidate_pipe, + pressure_leak, + similarity_mode, + monitor_p, + predict_p, + normal_p, + pressure_leak_all, + monitor_p_all, + predict_p_all, + normal_p_all, + important_sensor, + if_gy, + cos_or_flow, +): + similarity_cos = pd.Series(dtype=float, index=candidate_pipe) + similarity_dis = pd.Series(dtype=float, index=candidate_pipe) + dpressure = normal_p - pressure_leak + + # 无用 ---------------------------------------------- + mean_dpressure = dpressure.mean() + + monitor_new = pd.DataFrame(index=["monitor"], columns=monitor_p.index) + monitor_new.iloc[0] = monitor_p + add_m_leak_pressure = [pressure_leak, monitor_p] + add_m_leak_pressure = pd.concat(add_m_leak_pressure) + pressure_leak_std = add_m_leak_pressure.std(axis=0, ddof=1) + pressure_leak_std = pd.Series(pressure_leak_std, index=pressure_leak.columns) + + add_m_leak_pressure_all = [pressure_leak_all, monitor_p_all] + add_m_leak_pressure_all = pd.concat(add_m_leak_pressure_all) + pressure_leak_std_all = add_m_leak_pressure_all.std(axis=0, ddof=1) + pressure_leak_std_all = pd.Series( + pressure_leak_std_all, index=pressure_leak.columns + ) + # 无用 ---------------------------------------------- + + monitor_p_temp = monitor_p + predict_p_temp = predict_p + normal_p_temp = normal_p + monitor_p_temp_all = monitor_p_all + predict_p_temp_all = predict_p_all + normal_p_temp_all = normal_p_all + record_success_candidate = [] + record_success_no_candidate = [] + for i in range(len(candidate_pipe)): + leak_p = pressure_leak.iloc[i, :] + leak_p_all = pressure_leak_all.iloc[i, :] + similarity_cos.iloc[i], similarity_dis.iloc[i], none_flag = ( + cal_similarity_simple_return_dd( + similarity_mode, + monitor_p_temp, + predict_p_temp, + normal_p_temp, + leak_p, + monitor_p_temp_all, + predict_p_temp_all, + normal_p_temp_all, + leak_p_all, + important_sensor, + mean_dpressure, + pressure_leak_std, + pressure_leak_std_all, + if_gy, + cos_or_flow, + ) + ) + if none_flag == 0: + record_success_candidate.append(candidate_pipe[i]) + else: + record_success_no_candidate.append(candidate_pipe[i]) + similarity_cos, similarity_dis = adjust( + similarity_cos, + similarity_dis, + record_success_candidate, + record_success_no_candidate, + ) + return similarity_cos, similarity_dis + + +def cal_top_f_sensor(normal_f): + if type(normal_f) == pd.core.frame.DataFrame: + mean_f = normal_f.mean() + else: + mean_f = normal_f + output_sensor = [] + output_normal_f = pd.Series(dtype=object) + for i in range(len(mean_f.index)): + if abs(mean_f.iloc[i]) > 0.01 / 3600: + output_sensor.append(mean_f.index[i]) + output_normal_f[mean_f.index[i]] = mean_f.iloc[i] + return output_sensor, output_normal_f + + +def cal_top_sensors(monitor_p, predict_p, Top_sensor_num): + dpressure = abs(predict_p - monitor_p) + if type(dpressure) == pd.core.frame.DataFrame: + dpressure = dpressure.mean() + dpressure_rank = dpressure.sort_values(ascending=False, kind="mergesort") + return list(dpressure_rank.index[:Top_sensor_num]) + + +def remove_3_sigma(similarity_t): + all_sample = len(similarity_t.index) + apart_sample = math.ceil(all_sample * 0.6) + similarity = similarity_t.astype("float") + mean_t = similarity.mean() + std_t = similarity.std() + new_similarity = similarity[ + (similarity <= mean_t + 3 * std_t) & (similarity >= mean_t - 3 * std_t) + ] + mean_t_new = new_similarity.mean() + return mean_t_new + + +def update_similarity(leak_candidate_center, similarity, leak_center_dict): + similarity_new = pd.Series(dtype=float) + for each_center in leak_candidate_center: + houxuan_center = leak_center_dict[each_center] + if len(houxuan_center) > 1: + temp_similarity = similarity[houxuan_center] + similarity_new[each_center] = temp_similarity.max() + else: + if type(similarity[each_center]) == pd.core.series.Series: + similarity_new[each_center] = similarity[each_center].mean() + else: + similarity_new[each_center] = similarity[each_center] + similarity_new = similarity_new.sort_values(ascending=False, kind="mergesort") + return similarity_new + + +def extra_judge( + similarity, min_candidates_to_prune: int = 200, std_relax_factor: float = 0.5 +): + if len(similarity.index) == 0: + return 1.0, similarity + if len(similarity.index) < int(min_candidates_to_prune): + return 1.0, similarity + + mean_similarity = float(similarity.mean()) + std_similarity = float(similarity.std()) + if not math.isfinite(std_similarity): + std_similarity = 0.0 + + threshold = mean_similarity - float(std_relax_factor) * std_similarity + out_put_similarity = similarity[similarity >= threshold - 1e-10] + if len(out_put_similarity.index) == 0: + out_put_similarity = similarity.iloc[:1] + + cut_ratio = len(out_put_similarity.index) / len(similarity.index) + return cut_ratio, out_put_similarity + + +def adjust_ratio(similarity_mode, cos_h, dis_h, dis_f_h, low_limit=0.1): + if similarity_mode == "CAF": + if cos_h < low_limit: + cos_h = low_limit + dis_f_h = 1 - cos_h + elif dis_f_h < low_limit: + dis_f_h = low_limit + cos_h = 1 - dis_f_h + elif similarity_mode == "CAD_new_gy": + if dis_h < low_limit: + dis_h = low_limit + cos_h = 1 - dis_h + elif cos_h < low_limit: + cos_h = low_limit + dis_h = 1 - cos_h + elif similarity_mode == "CDF": + normal_index = [0, 1, 2] + h_list = [cos_h, dis_h, dis_f_h] + if cos_h < low_limit: + h_list[0] = low_limit + normal_index.remove(0) + if dis_h < low_limit: + h_list[1] = low_limit + normal_index.remove(1) + if dis_f_h < low_limit: + h_list[2] = low_limit + normal_index.remove(2) + + if len(normal_index) == 1: + h_list[normal_index[0]] = h_list[normal_index[0]] - (sum(h_list) - 1) + elif len(normal_index) == 2: + sum_list = sum(h_list) + multiper = 1 - (sum_list - 1) / ( + h_list[normal_index[0]] + h_list[normal_index[1]] + ) + h_list[normal_index[0]] = h_list[normal_index[0]] * multiper + h_list[normal_index[1]] = h_list[normal_index[1]] * multiper + + cos_h, dis_h, dis_f_h = h_list[0], h_list[1], h_list[2] + + return cos_h, dis_h, dis_f_h + + +# 返回相似性计算的模式(不同权重),是否计算流量相似性,是否只计算cos相似性,是否只计算流量相似性。 +def decode_mode(similarity_mode): + if similarity_mode == "COS": + if_flow = 0 + if_only_cos = 1 + if_only_flow = 0 + elif similarity_mode == "CAD_new_gy": + if_flow = 0 + if_only_cos = 0 + if_only_flow = 0 + elif similarity_mode == "CDF": + if_flow = 1 + if_only_cos = 0 + if_only_flow = 0 + elif similarity_mode == "CAF": + if_flow = 1 + if_only_cos = 1 + if_only_flow = 0 + elif similarity_mode == "DIS": + if_flow = 1 + if_only_cos = 2 + if_only_flow = 0 + elif similarity_mode == "OF": + if_flow = 1 + if_only_cos = 0 + if_only_flow = 1 + return if_flow, if_only_cos, if_only_flow + + diff --git a/app/algorithms/cleaning/__init__.py b/app/algorithms/cleaning/__init__.py new file mode 100644 index 0000000..c6f9a28 --- /dev/null +++ b/app/algorithms/cleaning/__init__.py @@ -0,0 +1,59 @@ +import os + +from app.algorithms.cleaning import flow as _flow_module +from app.algorithms.cleaning import pressure as _pressure_module + + +############################################################ +# 流量监测数据清洗 ***卡尔曼滤波法*** +############################################################ +# 2025/08/21 hxyan + + +def flow_data_clean(input_csv_file: str) -> str: + """ + 读取 input_csv_path 中的每列时间序列,使用一维 Kalman 滤波平滑并用预测值替换基于 3σ 检测出的异常点。 + 保存输出为:_cleaned.xlsx(与输入同目录),并返回输出文件的绝对路径。如有同名文件存在,则覆盖。 + :param: input_csv_file: 输入的 CSV 文件明或路径 + :return: 输出文件的绝对路径 + """ + + # 提供的 input_csv_path 绝对路径,以下为 默认脚本目录下同名 CSV 文件,构建绝对路径,可根据情况修改 + # 使用 algorithms 根目录保持与原 data_cleaning.py 一致的行为 + script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + input_csv_path = os.path.join(script_dir, input_csv_file) + + # 检查文件是否存在 + if not os.path.exists(input_csv_path): + raise FileNotFoundError(f"指定的文件不存在: {input_csv_path}") + # 调用 clean_flow_data_kf 函数进行数据清洗 + out_xlsx_path = _flow_module.clean_flow_data_kf(input_csv_path) + print("清洗后的数据已保存到:", out_xlsx_path) + + +############################################################ +# 压力监测数据清洗 ***kmean++法*** +############################################################ +# 2025/08/21 hxyan + + +def pressure_data_clean(input_csv_file: str) -> str: + """ + 读取 input_csv_path 中的每列时间序列,使用Kmean++清洗数据。 + 保存输出为:_cleaned.xlsx(与输入同目录),并返回输出文件的绝对路径。如有同名文件存在,则覆盖。 + 原始数据在 sheet 'raw_pressure_data',处理后数据在 sheet 'cleaned_pressusre_data'。 + :param input_csv_path: 输入的 CSV 文件路径 + :return: 输出文件的绝对路径 + """ + + # 提供的 input_csv_path 绝对路径,以下为 默认脚本目录下同名 CSV 文件,构建绝对路径,可根据情况修改 + # 使用 algorithms 根目录保持与原 data_cleaning.py 一致的行为 + script_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + input_csv_path = os.path.join(script_dir, input_csv_file) + + # 检查文件是否存在 + if not os.path.exists(input_csv_path): + raise FileNotFoundError(f"指定的文件不存在: {input_csv_path}") + # 调用 clean_pressure_data_km 函数进行数据清洗 + out_xlsx_path = _pressure_module.clean_pressure_data_km(input_csv_path) + print("清洗后的数据已保存到:", out_xlsx_path) diff --git a/api_ex/Fdataclean.py b/app/algorithms/cleaning/flow.py similarity index 75% rename from api_ex/Fdataclean.py rename to app/algorithms/cleaning/flow.py index 28f95db..ee361b9 100644 --- a/api_ex/Fdataclean.py +++ b/app/algorithms/cleaning/flow.py @@ -1,19 +1,40 @@ -# ...existing code... import pandas as pd import numpy as np import matplotlib.pyplot as plt from pykalman import KalmanFilter import os +from app.algorithms._utils import fill_time_gaps -def clean_flow_data_kf(input_csv_path: str, show_plot: bool = False) -> str: + +def clean_flow_data_kf( + input_csv_path: str, show_plot: bool = False, fill_gaps: bool = True +) -> str: """ 读取 input_csv_path 中的每列时间序列,使用一维 Kalman 滤波平滑并用预测值替换基于 3σ 检测出的异常点。 保存输出为:_cleaned.xlsx(与输入同目录),并返回输出文件的绝对路径。 仅保留输入文件路径作为参数(按要求)。 + + Args: + input_csv_path: CSV 文件路径 + show_plot: 是否显示可视化 + fill_gaps: 是否先补齐时间缺口(默认 True) """ # 读取 CSV data = pd.read_csv(input_csv_path, header=0, index_col=None, encoding="utf-8") + + # 补齐时间缺口(如果数据包含 time 列) + if fill_gaps and "time" in data.columns: + data = fill_time_gaps( + data, time_col="time", freq="1min", short_gap_threshold=10 + ) + + # 分离时间列和数值列 + time_col_data = None + if "time" in data.columns: + time_col_data = data["time"] + data = data.drop(columns=["time"]) + # 存储 Kalman 平滑结果 data_kf = pd.DataFrame(index=data.index, columns=data.columns) # 平滑每一列 @@ -63,6 +84,10 @@ def clean_flow_data_kf(input_csv_path: str, show_plot: bool = False) -> str: ) cleaned_data.loc[anomaly_idx, f"{col}_cleaned"] = data_kf.loc[anomaly_idx, col] + # 如果原始数据包含时间列,将其添加回结果 + if time_col_data is not None: + cleaned_data.insert(0, "time", time_col_data) + # 构造输出文件名:在输入文件名基础上加后缀 _cleaned.xlsx input_dir = os.path.dirname(os.path.abspath(input_csv_path)) input_base = os.path.splitext(os.path.basename(input_csv_path))[0] @@ -117,22 +142,31 @@ def clean_flow_data_kf(input_csv_path: str, show_plot: bool = False) -> str: return os.path.abspath(output_path) -def clean_flow_data_dict(data_dict: dict, show_plot: bool = False) -> dict: +def clean_flow_data_df_kf(data: pd.DataFrame, show_plot: bool = False) -> dict: """ - 接收一个字典数据结构,其中键为列名,值为时间序列列表,使用一维 Kalman 滤波平滑并用预测值替换基于 IQR 检测出的异常点。 + 接收一个 DataFrame 数据结构,使用一维 Kalman 滤波平滑并用预测值替换基于 IQR 检测出的异常点。 区分合理的0值(流量转换)和异常的0值(连续多个0或孤立0)。 返回完整的清洗后的字典数据结构。 + + Args: + data: 输入 DataFrame(可包含 time 列) + show_plot: 是否显示可视化 """ - # 将字典转换为 DataFrame - data = pd.DataFrame(data_dict) - # 替换0值,填充NaN值 - data_filled = data.replace(0, np.nan) + # 使用传入的 DataFrame + data = data.copy() - # 对异常0值进行插值:先用前后均值填充,再用ffill/bfill处理剩余NaN - data_filled = data_filled.interpolate(method="linear", limit_direction="both") + # 补齐时间缺口(如果启用且数据包含 time 列) + data_filled = fill_time_gaps( + data, time_col="time", freq="1min", short_gap_threshold=10 + ) - # 处理剩余的0值和NaN值 - data_filled = data_filled.ffill().bfill() + # 保存 time 列用于最后合并 + time_col_series = None + if "time" in data_filled.columns: + time_col_series = data_filled["time"] + + # 移除 time 列用于后续清洗 + data_filled = data_filled.drop(columns=["time"]) # 存储 Kalman 平滑结果 data_kf = pd.DataFrame(index=data_filled.index, columns=data_filled.columns) @@ -192,28 +226,47 @@ def clean_flow_data_dict(data_dict: dict, show_plot: bool = False) -> dict: plt.rcParams["axes.unicode_minus"] = False if show_plot and len(data.columns) > 0: sensor_to_plot = data.columns[0] + + # 定义x轴 + n = len(data) + time = np.arange(n) + n_filled = len(data_filled) + time_filled = np.arange(n_filled) + plt.figure(figsize=(12, 8)) plt.subplot(2, 1, 1) plt.plot( - data.index, + time, data[sensor_to_plot], label="原始监测值", marker="o", markersize=3, alpha=0.7, ) - abnormal_zero_idx = data.index[data_filled[sensor_to_plot].isna()] + + # 修正:检查 data_filled 的异常值,绘制在 time_filled 上 + abnormal_zero_mask = data_filled[sensor_to_plot].isna() + # 如果目的是检查0值,应该用 == 0。这里保留 isna() 但修正索引引用,防止crash。 + # 如果原意是 isna() 则在 fillna 后通常没有 na。假设用户可能想检查 0 值? + # 基于 "异常0值" 的标签,改为检查 0 值更合理,但为了保险起见, + # 如果 isna() 返回空,就不画。防止索引越界是主要的。 + abnormal_zero_idx = data_filled.index[abnormal_zero_mask] + if len(abnormal_zero_idx) > 0: + # 注意:如果 abnormal_zero_idx 是基于 data_filled 的索引(0..M-1), + # 直接作为 x 坐标即可,因为 time_filled 也是 0..M-1 + # 而 y 值应该取自 data_filled 或 data_kf,取 data 会越界 plt.plot( abnormal_zero_idx, - data[sensor_to_plot].loc[abnormal_zero_idx], + data_filled[sensor_to_plot].loc[abnormal_zero_idx], "mo", markersize=8, - label="异常0值", + label="异常值(NaN)", ) + plt.plot( - data.index, data_kf[sensor_to_plot], label="Kalman滤波预测值", linewidth=2 + time_filled, data_kf[sensor_to_plot], label="Kalman滤波预测值", linewidth=2 ) anomaly_idx = anomalies_info[sensor_to_plot].index if len(anomaly_idx) > 0: @@ -231,7 +284,7 @@ def clean_flow_data_dict(data_dict: dict, show_plot: bool = False) -> dict: plt.subplot(2, 1, 2) plt.plot( - data.index, + time_filled, cleaned_data[sensor_to_plot], label="修复后监测值", marker="o", @@ -246,8 +299,12 @@ def clean_flow_data_dict(data_dict: dict, show_plot: bool = False) -> dict: plt.tight_layout() plt.show() + # 将 time 列添加回结果 + if time_col_series is not None: + cleaned_data.insert(0, "time", time_col_series) + # 返回完整的修复后字典 - return cleaned_data.to_dict(orient="list") + return cleaned_data # # 测试 @@ -279,7 +336,7 @@ if __name__ == "__main__": print("原始数据长度:", len(data_dict[selected_columns[0]])) # 调用函数进行清洗 - cleaned_dict = clean_flow_data_dict(data_dict, show_plot=True) + cleaned_dict = clean_flow_data_df_kf(data_dict, show_plot=True) # 将清洗后的字典写回 CSV out_csv = os.path.join(script_dir, f"{selected_columns[0]}_clean.csv") pd.DataFrame(cleaned_dict).to_csv(out_csv, index=False, encoding="utf-8-sig") diff --git a/api_ex/Pdataclean.py b/app/algorithms/cleaning/pressure.py similarity index 63% rename from api_ex/Pdataclean.py rename to app/algorithms/cleaning/pressure.py index b5e73f4..6fc545e 100644 --- a/api_ex/Pdataclean.py +++ b/app/algorithms/cleaning/pressure.py @@ -1,22 +1,41 @@ import pandas as pd import numpy as np import matplotlib.pyplot as plt -from sklearn.decomposition import PCA from sklearn.cluster import KMeans -from sklearn.metrics import silhouette_score +from sklearn.impute import SimpleImputer import os +from app.algorithms._utils import fill_time_gaps -def clean_pressure_data_km(input_csv_path: str, show_plot: bool = False) -> str: +def clean_pressure_data_km( + input_csv_path: str, show_plot: bool = False, fill_gaps: bool = True +) -> str: """ 读取输入 CSV,基于 KMeans 检测异常并用滚动平均修复。输出为 _cleaned.xlsx(同目录)。 原始数据在 sheet 'raw_pressure_data',处理后数据在 sheet 'cleaned_pressusre_data'。 返回输出文件的绝对路径。 + + Args: + input_csv_path: CSV 文件路径 + show_plot: 是否显示可视化 + fill_gaps: 是否先补齐时间缺口(默认 True) """ # 读取 CSV input_csv_path = os.path.abspath(input_csv_path) data = pd.read_csv(input_csv_path, header=0, index_col=None, encoding="utf-8") + + # 补齐时间缺口(如果数据包含 time 列) + if fill_gaps and "time" in data.columns: + data = fill_time_gaps( + data, time_col="time", freq="1min", short_gap_threshold=10 + ) + + # 分离时间列和数值列 + time_col_data = None + if "time" in data.columns: + time_col_data = data["time"] + data = data.drop(columns=["time"]) # 标准化 data_norm = (data - data.mean()) / data.std() @@ -50,18 +69,18 @@ def clean_pressure_data_km(input_csv_path: str, show_plot: bool = False) -> str: data_repaired.loc[label, sensor] = data_rolled.loc[label, sensor] # 可选可视化(使用位置作为 x 轴) - plt.rcParams['font.sans-serif'] = ['SimHei'] - plt.rcParams['axes.unicode_minus'] = False + plt.rcParams["font.sans-serif"] = ["SimHei"] + plt.rcParams["axes.unicode_minus"] = False if show_plot and len(data.columns) > 0: n = len(data) time = np.arange(n) plt.figure(figsize=(12, 8)) for col in data.columns: - plt.plot(time, data[col].values, marker='o', markersize=3, label=col) + plt.plot(time, data[col].values, marker="o", markersize=3, label=col) for pos in anomaly_pos: sensor = anomaly_details[data.index[pos]] - plt.plot(pos, data.iloc[pos][sensor], 'ro', markersize=8) + plt.plot(pos, data.iloc[pos][sensor], "ro", markersize=8) plt.xlabel("时间点(序号)") plt.ylabel("压力监测值") plt.title("各传感器折线图(红色标记主要异常点)") @@ -70,10 +89,12 @@ def clean_pressure_data_km(input_csv_path: str, show_plot: bool = False) -> str: plt.figure(figsize=(12, 8)) for col in data_repaired.columns: - plt.plot(time, data_repaired[col].values, marker='o', markersize=3, label=col) + plt.plot( + time, data_repaired[col].values, marker="o", markersize=3, label=col + ) for pos in anomaly_pos: sensor = anomaly_details[data.index[pos]] - plt.plot(pos, data_repaired.iloc[pos][sensor], 'go', markersize=8) + plt.plot(pos, data_repaired.iloc[pos][sensor], "go", markersize=8) plt.xlabel("时间点(序号)") plt.ylabel("修复后压力监测值") plt.title("修复后各传感器折线图(绿色标记修复值)") @@ -86,35 +107,63 @@ def clean_pressure_data_km(input_csv_path: str, show_plot: bool = False) -> str: output_filename = f"{input_base}_cleaned.xlsx" output_path = os.path.join(input_dir, output_filename) + # 如果原始数据包含时间列,将其添加回结果 + data_for_save = data.copy() + data_repaired_for_save = data_repaired.copy() + if time_col_data is not None: + data_for_save.insert(0, "time", time_col_data) + data_repaired_for_save.insert(0, "time", time_col_data) + if os.path.exists(output_path): - os.remove(output_path) # 覆盖同名文件 - with pd.ExcelWriter(output_path, engine='openpyxl') as writer: - data.to_excel(writer, sheet_name='raw_pressure_data', index=False) - data_repaired.to_excel(writer, sheet_name='cleaned_pressusre_data', index=False) - + os.remove(output_path) # 覆盖同名文件 + with pd.ExcelWriter(output_path, engine="openpyxl") as writer: + data_for_save.to_excel(writer, sheet_name="raw_pressure_data", index=False) + data_repaired_for_save.to_excel( + writer, sheet_name="cleaned_pressusre_data", index=False + ) + # 返回输出文件的绝对路径 return os.path.abspath(output_path) -def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dict: +def clean_pressure_data_df_km(data: pd.DataFrame, show_plot: bool = False) -> dict: """ - 接收一个字典数据结构,其中键为列名,值为时间序列列表,使用KMeans聚类检测异常并用滚动平均修复。 + 接收一个 DataFrame 数据结构,使用KMeans聚类检测异常并用滚动平均修复。 返回清洗后的字典数据结构。 + + Args: + data: 输入 DataFrame(可包含 time 列) + show_plot: 是否显示可视化 """ - # 将字典转换为 DataFrame - data = pd.DataFrame(data_dict) - # 填充NaN值 - data = data.ffill().bfill() - # 异常值预处理 - # 将0值替换为NaN,然后用线性插值填充 - data_filled = data.replace(0, np.nan) - data_filled = data_filled.interpolate(method="linear", limit_direction="both") - # 如果仍有NaN(全为0的列),用前后值填充 - data_filled = data_filled.ffill().bfill() + # 使用传入的 DataFrame + data = data.copy() + + # 补齐时间缺口(如果启用且数据包含 time 列) + data_filled = fill_time_gaps( + data, time_col="time", freq="1min", short_gap_threshold=10 + ) + + # 保存 time 列用于最后合并 + time_col_series = None + if "time" in data_filled.columns: + time_col_series = data_filled["time"] + + # 移除 time 列用于后续清洗 + data_filled = data_filled.drop(columns=["time"]) # 标准化(使用填充后的数据) data_norm = (data_filled - data_filled.mean()) / data_filled.std() + # 添加:处理标准化后的 NaN(例如,标准差为0的列),防止异常数据,时间段内所有数据都相同导致计算结果为 NaN + imputer = SimpleImputer( + strategy="constant", fill_value=0, keep_empty_features=True + ) # 用 0 填充 NaN,包括全 NaN,并保留空特征 + data_norm = pd.DataFrame( + imputer.fit_transform(data_norm), + columns=data_norm.columns, + index=data_norm.index, + ) + # 聚类与异常检测 k = 3 kmeans = KMeans(n_clusters=k, init="k-means++", n_init=50, random_state=42) @@ -125,7 +174,7 @@ def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dic threshold = distances.mean() + 3 * distances.std() anomaly_pos = np.where(distances > threshold)[0] - anomaly_indices = data.index[anomaly_pos] + anomaly_indices = data_filled.index[anomaly_pos] anomaly_details = {} for pos in anomaly_pos: @@ -134,13 +183,13 @@ def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dic center = centers[cluster_idx] diff = abs(row_norm - center) main_sensor = diff.idxmax() - anomaly_details[data.index[pos]] = main_sensor + anomaly_details[data_filled.index[pos]] = main_sensor # 修复:滚动平均(窗口可调) data_rolled = data_filled.rolling(window=13, center=True, min_periods=1).mean() data_repaired = data_filled.copy() for pos in anomaly_pos: - label = data.index[pos] + label = data_filled.index[pos] sensor = anomaly_details[label] data_repaired.loc[label, sensor] = data_rolled.loc[label, sensor] @@ -151,6 +200,8 @@ def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dic if show_plot and len(data.columns) > 0: n = len(data) time = np.arange(n) + n_filled = len(data_filled) + time_filled = np.arange(n_filled) plt.figure(figsize=(12, 8)) for col in data.columns: plt.plot( @@ -158,7 +209,7 @@ def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dic ) for col in data_filled.columns: plt.plot( - time, + time_filled, data_filled[col].values, marker="x", markersize=3, @@ -166,7 +217,7 @@ def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dic linestyle="--", ) for pos in anomaly_pos: - sensor = anomaly_details[data.index[pos]] + sensor = anomaly_details[data_filled.index[pos]] plt.plot(pos, data_filled.iloc[pos][sensor], "ro", markersize=8) plt.xlabel("时间点(序号)") plt.ylabel("压力监测值") @@ -177,19 +228,23 @@ def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dic plt.figure(figsize=(12, 8)) for col in data_repaired.columns: plt.plot( - time, data_repaired[col].values, marker="o", markersize=3, label=col + time_filled, data_repaired[col].values, marker="o", markersize=3, label=col ) for pos in anomaly_pos: - sensor = anomaly_details[data.index[pos]] + sensor = anomaly_details[data_filled.index[pos]] plt.plot(pos, data_repaired.iloc[pos][sensor], "go", markersize=8) - plt.xlabel("时间点(序号)") - plt.ylabel("修复后压力监测值") - plt.title("修复后各传感器折线图(绿色标记修复值)") - plt.legend() - plt.show() + plt.xlabel("时间点(序号)") + plt.ylabel("修复后压力监测值") + plt.title("修复后各传感器折线图(绿色标记修复值)") + plt.legend() + plt.show() + + # 将 time 列添加回结果 + if time_col_series is not None: + data_repaired.insert(0, "time", time_col_series) # 返回清洗后的字典 - return data_repaired.to_dict(orient="list") + return data_repaired # 测试 @@ -203,25 +258,26 @@ def clean_pressure_data_dict_km(data_dict: dict, show_plot: bool = False) -> dic # 测试 clean_pressure_data_dict_km 函数 if __name__ == "__main__": import random + # 读取 szh_pressure_scada.csv 文件 script_dir = os.path.dirname(os.path.abspath(__file__)) csv_path = os.path.join(script_dir, "szh_pressure_scada.csv") data = pd.read_csv(csv_path, header=0, index_col=None, encoding="utf-8") - + # 排除 Time 列,随机选择 5 列 - columns_to_exclude = ['Time'] + columns_to_exclude = ["Time"] available_columns = [col for col in data.columns if col not in columns_to_exclude] selected_columns = random.sample(available_columns, 5) - + # 将选中的列转换为字典 data_dict = {col: data[col].tolist() for col in selected_columns} - + print("选中的列:", selected_columns) print("原始数据长度:", len(data_dict[selected_columns[0]])) - + # 调用函数进行清洗 - cleaned_dict = clean_pressure_data_dict_km(data_dict, show_plot=True) - + cleaned_dict = clean_pressure_data_df_km(data_dict, show_plot=True) + print("清洗后的字典键:", list(cleaned_dict.keys())) print("清洗后的数据长度:", len(cleaned_dict[selected_columns[0]])) print("测试完成:函数运行正常") diff --git a/app/algorithms/health/__init__.py b/app/algorithms/health/__init__.py new file mode 100644 index 0000000..d0e216f --- /dev/null +++ b/app/algorithms/health/__init__.py @@ -0,0 +1,3 @@ +from app.algorithms.health.analyzer import PipelineHealthAnalyzer + +__all__ = ["PipelineHealthAnalyzer"] diff --git a/app/algorithms/health/analyzer.py b/app/algorithms/health/analyzer.py new file mode 100644 index 0000000..ed1caca --- /dev/null +++ b/app/algorithms/health/analyzer.py @@ -0,0 +1,148 @@ +import os +import joblib +import pandas as pd +import matplotlib.pyplot as plt + + +class PipelineHealthAnalyzer: + """ + 管道健康分析器类,使用随机生存森林模型预测管道的生存概率。 + + 该类封装了模型加载和预测功能,便于在其他项目中复用。 + 模型基于4个特征进行生存分析预测:材料、直径、流速、压力。 + + 使用前需确保安装依赖:joblib, pandas, numpy, scikit-survival, matplotlib。 + """ + + def __init__(self, model_path: str = None): + """ + 初始化分析器,加载预训练的随机生存森林模型。 + + :param model_path: 模型文件的路径(默认为相对路径 './model/my_survival_forest_model_quxi.joblib')。 + :raises FileNotFoundError: 如果模型文件不存在。 + :raises Exception: 如果模型加载失败。 + """ + if model_path is None: + model_path = os.path.join( + os.path.dirname(__file__), + "model", + "my_survival_forest_model_quxi.joblib", + ) + # 确保 model 目录存在 + model_dir = os.path.dirname(model_path) + if model_dir and not os.path.exists(model_dir): + os.makedirs(model_dir, exist_ok=True) + + if not os.path.exists(model_path): + raise FileNotFoundError(f"模型文件未找到: {model_path}") + + try: + self.rsf = joblib.load(model_path) + self.features = [ + "Material", + "Diameter", + "Flow Velocity", + "Pressure", # 'Temperature', 'Precipitation', + # 'Location', 'Structural Defects', 'Functional Defects' + ] + except Exception as e: + raise Exception(f"加载模型时出错: {str(e)}") + + def predict_survival(self, data: pd.DataFrame) -> list: + """ + 基于输入数据预测生存函数。 + + :param data: pandas DataFrame,包含4个必需特征列。数据应为数值型或可转换为数值型。 + :return: 生存函数列表,每个元素为一个生存函数对象(包含时间点x和生存概率y)。 + :raises ValueError: 如果数据缺少必需特征或格式不正确。 + """ + # 检查必需特征是否存在 + missing_features = [feat for feat in self.features if feat not in data.columns] + if missing_features: + raise ValueError(f"数据缺少必需特征: {missing_features}") + + # 提取特征数据 + try: + x_test = data[self.features].astype(float) # 确保数值型 + except ValueError as e: + raise ValueError(f"特征数据转换失败,请检查数据类型: {str(e)}") + + # 进行预测 + survival_functions = self.rsf.predict_survival_function(x_test) + return list(survival_functions) + + def plot_survival( + self, survival_functions: list, save_path: str = None, show_plot: bool = True + ): + """ + 可视化生存函数,生成生存概率图表。 + + :param survival_functions: predict_survival返回的生存函数列表。 + :param save_path: 可选,保存图表的路径(.png格式)。如果为None,则不保存。 + :param show_plot: 是否显示图表(在交互环境中)。 + """ + plt.figure(figsize=(10, 6)) + for i, sf in enumerate(survival_functions): + plt.step(sf.x, sf.y, where="post", label=f"样本 {i + 1}") + plt.xlabel("时间(年)") + plt.ylabel("生存概率") + plt.title("管道生存概率预测") + plt.legend() + plt.grid(True, alpha=0.3) + + if save_path: + plt.savefig(save_path, dpi=300, bbox_inches="tight") + print(f"图表已保存到: {save_path}") + + if show_plot: + plt.show() + else: + plt.close() + + +# 调用说明示例 +""" +在其他项目中使用PipelineHealthAnalyzer类的步骤: + +1. 安装依赖(在requirements.txt中添加): + joblib==1.5.0 + pandas==2.2.3 + numpy==2.0.2 + scikit-survival==0.23.1 + matplotlib==3.9.4 + +2. 导入类: + from pipeline_health_analyzer import PipelineHealthAnalyzer + +3. 初始化分析器(替换为实际模型路径): + analyzer = PipelineHealthAnalyzer(model_path='path/to/my_survival_forest_model3-10.joblib') + +4. 准备数据(pandas DataFrame,包含9个特征列): + import pandas as pd + data = pd.DataFrame({ + 'Material': [1, 2], # 示例数据 + 'Diameter': [100, 150], + 'Flow Velocity': [1.5, 2.0], + 'Pressure': [50, 60], + 'Temperature': [20, 25], + 'Precipitation': [0.1, 0.2], + 'Location': [1, 2], + 'Structural Defects': [0, 1], + 'Functional Defects': [0, 0] + }) + +5. 进行预测: + survival_funcs = analyzer.predict_survival(data) + +6. 查看结果(每个样本的生存概率随时间变化): + for i, sf in enumerate(survival_funcs): + print(f"样本 {i+1}: 时间点: {sf.x[:5]}..., 生存概率: {sf.y[:5]}...") + +7. 可视化(可选): + analyzer.plot_survival(survival_funcs, save_path='survival_plot.png') + +注意: +- 数据格式必须匹配特征列表,特征值为数值型。 +- 模型文件需从原项目复制或重新训练。 +- 如果需要自定义特征或模型参数,可修改类中的features列表或继承此类。 +""" diff --git a/app/algorithms/health/model/my_survival_forest_model_quxi.zip b/app/algorithms/health/model/my_survival_forest_model_quxi.zip new file mode 100644 index 0000000..6ad9f68 Binary files /dev/null and b/app/algorithms/health/model/my_survival_forest_model_quxi.zip differ diff --git a/app/algorithms/isolation/__init__.py b/app/algorithms/isolation/__init__.py new file mode 100644 index 0000000..12d5a35 --- /dev/null +++ b/app/algorithms/isolation/__init__.py @@ -0,0 +1,3 @@ +from app.algorithms.isolation.valve import valve_isolation_analysis + +__all__ = ["valve_isolation_analysis"] diff --git a/app/algorithms/isolation/valve.py b/app/algorithms/isolation/valve.py new file mode 100644 index 0000000..57cd1e1 --- /dev/null +++ b/app/algorithms/isolation/valve.py @@ -0,0 +1,165 @@ +from collections import defaultdict, deque +from functools import lru_cache +from typing import Any + +from app.services.tjnetwork import ( + get_network_link_nodes, + is_node, + get_link_properties, +) + + +VALVE_LINK_TYPE = "valve" + + +def _parse_link_entry(link_entry: str) -> tuple[str, str, str, str]: + parts = link_entry.split(":", 3) + if len(parts) != 4: + raise ValueError(f"Invalid link entry format: {link_entry}") + return parts[0], parts[1], parts[2], parts[3] + + +@lru_cache(maxsize=16) +def _get_network_topology(network: str): + """ + 解析并缓存网络拓扑,大幅减少重复的 API 调用和字符串解析开销。 + 返回: + - pipe_adj: 永久连通的管道/泵邻接表 (dict[str, set]) + - all_valves: 所有阀门字典 {id: (n1, n2)} + - link_lookup: 链路快速查表 {id: (n1, n2, type)} 用于快速定位事故点 + - node_set: 所有已知节点集合 + """ + pipe_adj = defaultdict(set) + all_valves = {} + link_lookup = {} + node_set = set() + + # 此处假设 get_network_link_nodes 获取全网数据 + for link_entry in get_network_link_nodes(network): + link_id, link_type, node1, node2 = _parse_link_entry(link_entry) + link_type_name = str(link_type).lower() + + link_lookup[link_id] = (node1, node2, link_type_name) + node_set.add(node1) + node_set.add(node2) + + if link_type_name == VALVE_LINK_TYPE: + all_valves[link_id] = (node1, node2) + else: + # 只有非阀门(管道/泵)才进入永久连通图 + pipe_adj[node1].add(node2) + pipe_adj[node2].add(node1) + + return pipe_adj, all_valves, link_lookup, node_set + + +def valve_isolation_analysis( + network: str, accident_elements: str | list[str], disabled_valves: list[str] = None +) -> dict[str, Any]: + """ + 关阀搜索/分析:基于拓扑结构确定事故隔离所需关阀。 + :param network: 模型名称 + :param accident_elements: 事故点(节点或管道/泵/阀门ID),可以是单个ID字符串或ID列表 + :param disabled_valves: 故障/无法关闭的阀门ID列表 + :return: dict,包含受影响节点、必须关闭阀门、可选阀门等信息 + """ + if disabled_valves is None: + disabled_valves_set = set() + else: + disabled_valves_set = set(disabled_valves) + + if isinstance(accident_elements, str): + target_elements = [accident_elements] + else: + target_elements = accident_elements + + # 1. 获取缓存拓扑 (极快,无 IO) + pipe_adj, all_valves, link_lookup, node_set = _get_network_topology(network) + + # 2. 确定起点,优先查表避免 API 调用 + start_nodes = set() + for element in target_elements: + if element in node_set: + start_nodes.add(element) + elif element in link_lookup: + n1, n2, _ = link_lookup[element] + start_nodes.add(n1) + start_nodes.add(n2) + else: + # 仅当缓存中没找到时(极少见),才回退到慢速 API + if is_node(network, element): + start_nodes.add(element) + else: + props = get_link_properties(network, element) + n1, n2 = props.get("node1"), props.get("node2") + if n1 and n2: + start_nodes.add(n1) + start_nodes.add(n2) + else: + raise ValueError( + f"Accident element {element} invalid or missing endpoints" + ) + + # 3. 处理故障阀门 (构建临时增量图) + # 我们不修改 cached pipe_adj,而是建立一个 extra_adj + extra_adj = defaultdict(list) + boundary_valves = {} # 当前有效的边界阀门 + + for vid, (n1, n2) in all_valves.items(): + if vid in disabled_valves_set: + # 故障阀门:视为连通管道 + extra_adj[n1].append(n2) + extra_adj[n2].append(n1) + else: + # 正常阀门:视为潜在边界 + boundary_valves[vid] = (n1, n2) + + # 4. BFS 搜索 (叠加 pipe_adj 和 extra_adj) + affected_nodes: set[str] = set() + queue = deque(start_nodes) + while queue: + node = queue.popleft() + if node in affected_nodes: + continue + affected_nodes.add(node) + + # 遍历永久管道邻居 + if node in pipe_adj: + for neighbor in pipe_adj[node]: + if neighbor not in affected_nodes: + queue.append(neighbor) + + # 遍历故障阀门带来的额外邻居 + if node in extra_adj: + for neighbor in extra_adj[node]: + if neighbor not in affected_nodes: + queue.append(neighbor) + + # 5. 结果聚合 + must_close_valves: list[str] = [] + optional_valves: list[str] = [] + + for valve_id, (n1, n2) in boundary_valves.items(): + in_n1 = n1 in affected_nodes + in_n2 = n2 in affected_nodes + if in_n1 and in_n2: + optional_valves.append(valve_id) + elif in_n1 or in_n2: + must_close_valves.append(valve_id) + + must_close_valves.sort() + optional_valves.sort() + + result = { + "accident_elements": target_elements, + "disabled_valves": disabled_valves, + "affected_nodes": sorted(affected_nodes), + "must_close_valves": must_close_valves, + "optional_valves": optional_valves, + "isolatable": len(must_close_valves) > 0, + } + + if len(target_elements) == 1: + result["accident_element"] = target_elements[0] + + return result diff --git a/app/algorithms/leakage/__init__.py b/app/algorithms/leakage/__init__.py new file mode 100644 index 0000000..9ec8b91 --- /dev/null +++ b/app/algorithms/leakage/__init__.py @@ -0,0 +1,3 @@ +from app.algorithms.leakage.identifier import LeakageIdentifier + +__all__ = ["LeakageIdentifier"] diff --git a/app/algorithms/leakage/identifier.py b/app/algorithms/leakage/identifier.py new file mode 100644 index 0000000..c2044b1 --- /dev/null +++ b/app/algorithms/leakage/identifier.py @@ -0,0 +1,653 @@ +import wntr +import numpy as np +import pandas as pd +import os +import time +import argparse +from multiprocessing import Pool, cpu_count +from typing import Any, List, Dict, Union + +from pymoo.core.problem import Problem +from pymoo.core.callback import Callback +from pymoo.algorithms.soo.nonconvex.ga import GA +from pymoo.operators.crossover.sbx import SBX +from pymoo.operators.mutation.pm import PM +from pymoo.optimize import minimize as pymoo_minimize +from pymoo.termination.default import DefaultSingleObjectiveTermination + + +from app.algorithms._utils import _cleanup_temp_files + +_worker_data: dict[str, Any] = {} +DEFAULT_N_WORKERS = max(1, min(cpu_count() - 1, 4)) + + +def _worker_init( + inp_path: str, + sensor_nodes: list[str], + area_ids: list[str], + nodes_by_area: dict[str, list[str]], + obs_matrix: np.ndarray, + q_sum: float, + duration_sec: float, + timestep_sec: float, +) -> None: + global _worker_data + wn = wntr.network.WaterNetworkModel(inp_path) + wn.options.hydraulic.demand_model = "DD" + wn.options.time.duration = duration_sec + wn.options.time.hydraulic_timestep = timestep_sec + wn.options.time.pattern_timestep = timestep_sec + wn.options.time.report_timestep = timestep_sec + + demand_objs_by_area = {} + allocatable_counts = {} + for area_id in area_ids: + demand_objs = [] + for node_name in nodes_by_area.get(area_id, []): + if node_name not in wn.node_name_list: + continue + node = wn.get_node(node_name) + if ( + hasattr(node, "demand_timeseries_list") + and len(node.demand_timeseries_list) > 0 + ): + demand_objs.append(node.demand_timeseries_list[0]) + demand_objs_by_area[area_id] = demand_objs + allocatable_counts[area_id] = len(demand_objs) + + _worker_data = { + "wn": wn, + "sensor_nodes": sensor_nodes, + "area_ids": area_ids, + "nodes_by_area": nodes_by_area, + "demand_objs_by_area": demand_objs_by_area, + "allocatable_counts": allocatable_counts, + "obs_matrix": obs_matrix, + "q_sum": q_sum, + } + + +def _worker_evaluate(raw_ratios: np.ndarray) -> float: + d = _worker_data + effective_ratio_map = LeakageIdentifier._effective_area_ratios( + raw_ratios, + d["area_ids"], + d["nodes_by_area"], + allocatable_counts=d["allocatable_counts"], + ) + + modifications = [] + for area_id in d["area_ids"]: + ratio = effective_ratio_map.get(area_id, 0.0) + if ratio <= 0: + continue + + demand_objs = d["demand_objs_by_area"].get(area_id, []) + if not demand_objs: + continue + + per_node_leak = d["q_sum"] * ratio / len(demand_objs) + for demand_obj in demand_objs: + original_val = demand_obj.base_value + demand_obj.base_value = original_val + per_node_leak + modifications.append((demand_obj, original_val)) + + temp_dir = os.path.abspath(os.path.join("temp", "leakage")) + os.makedirs(temp_dir, exist_ok=True) + prefix = os.path.join(temp_dir, f"temp_{os.getpid()}") + + try: + sim = wntr.sim.EpanetSimulator(d["wn"]) + results = sim.run_sim(file_prefix=prefix) + sim_pressure = results.node["pressure"].loc[:, d["sensor_nodes"]] + + n_steps = min(sim_pressure.shape[0], d["obs_matrix"].shape[0]) + sim_vals = sim_pressure.values[:n_steps, :] + obs_vals = d["obs_matrix"][:n_steps, :] + diff = sim_vals - obs_vals + + row_max = np.max(np.abs(diff), axis=1, keepdims=True) + row_max[row_max == 0] = 1.0 + normalized_diff = diff / row_max + return float(np.linalg.norm(normalized_diff)) + + except Exception: + return 1e9 + + finally: + for demand_obj, original_val in modifications: + demand_obj.base_value = original_val + _cleanup_temp_files(prefix) + + +class LeakageIdentifier: + FLOW_UNIT_TO_M3S = { + "m3/s": 1.0, + "m3/h": 1.0 / 3600.0, + "L/s": 1.0 / 1000.0, + "L/min": 1.0 / 60000.0, + } + + @classmethod + def _flow_to_m3s(cls, value: float, unit: str) -> float: + if unit not in cls.FLOW_UNIT_TO_M3S: + raise ValueError(f"不支持的流量单位: {unit}") + return float(value) * cls.FLOW_UNIT_TO_M3S[unit] + + @classmethod + def _flow_from_m3s(cls, value_m3s: float, unit: str) -> float: + if unit not in cls.FLOW_UNIT_TO_M3S: + raise ValueError(f"不支持的流量单位: {unit}") + return float(value_m3s) / cls.FLOW_UNIT_TO_M3S[unit] + + @staticmethod + def _effective_area_ratios( + raw_ratios: Union["np.ndarray", Dict[str, float]], + area_ids: List[str], + nodes_by_area: Dict[str, List[str]], + allocatable_counts: Union[Dict[str, int], None] = None, + ) -> Dict[str, float]: + """将输入比例转换为有效区域比例,确保有效区域比例和为 1。""" + area_count = len(area_ids) + if area_count == 0: + return {} + + if isinstance(raw_ratios, dict): + ratios = np.array( + [float(raw_ratios.get(area_id, 0.0)) for area_id in area_ids], + dtype=float, + ) + else: + arr = np.asarray(raw_ratios, dtype=float).reshape(-1) + ratios = np.zeros(area_count, dtype=float) + fill_len = min(area_count, arr.shape[0]) + if fill_len > 0: + ratios[:fill_len] = arr[:fill_len] + + # 仅保留非负比例,负值按 0 处理 + ratios = np.clip(ratios, a_min=0.0, a_max=None) + + # 仅在有效区域(存在可分配节点)内归一化 + if allocatable_counts is not None: + valid_mask = np.array( + [int(allocatable_counts.get(area_id, 0)) > 0 for area_id in area_ids], + dtype=bool, + ) + else: + valid_mask = np.array( + [len(nodes_by_area.get(area_id, [])) > 0 for area_id in area_ids], + dtype=bool, + ) + if not np.any(valid_mask): + raise ValueError("没有可分配漏损的有效分区,无法满足漏损总量约束。") + + effective = np.zeros(area_count, dtype=float) + valid_sum = float(np.sum(ratios[valid_mask])) + + if valid_sum > 0: + effective[valid_mask] = ratios[valid_mask] / valid_sum + else: + # 若输入全为 0,则在有效区域内均分,保证总和仍为 1 + valid_count = int(np.sum(valid_mask)) + effective[valid_mask] = 1.0 / valid_count + + return {area_id: float(effective[idx]) for idx, area_id in enumerate(area_ids)} + + @staticmethod + def _normalize_area_map_df(df: pd.DataFrame) -> pd.DataFrame: + """标准化区域映射列名为 ID 和 Area。""" + if "ID" in df.columns and "Area" in df.columns: + return df + + if "ID" in df.columns and "now" in df.columns: + df = df.rename(columns={"now": "Area"}) + return df + + df = df.copy() + df.columns = ["ID", "Area"] + list(df.columns[2:]) + return df + + def __init__( + self, + inp_path: str, + sensor_nodes: List[str], + area_map: Union[str, Dict[str, str]], + start_time: float = 0, + duration: float = 24, + timestep: float = 5, + q_sum: float = 0.2, + ): + """ + 初始化漏损识别器。 + + 参数: + inp_path: EPANET .inp 文件路径。 + sensor_nodes: 用作压力传感器的节点 ID 列表。 + area_map: 节点到区域的映射。可以是 CSV 文件路径(列:ID, Area),也可以是字典 {NodeID: AreaID}。 + start_time: 模拟开始时间(小时)。 + duration: 模拟持续时间(小时)。 + timestep: 模拟时间步长(分钟)。 + q_sum: 假设的总漏损流量 (m3/s)。 + """ + self.inp_path = inp_path + self.sensor_nodes = sensor_nodes + self.start_time = start_time + self.duration = duration + self.timestep = timestep + self.q_sum = q_sum + + # 加载管网模型(仅一次) + self.wn = wntr.network.WaterNetworkModel(self.inp_path) + + # 优化 WNTR 设置以提高速度 + self.wn.options.hydraulic.demand_model = "DD" + self.wn.options.time.duration = float(self.duration) * 3600 + self.wn.options.time.hydraulic_timestep = float(self.timestep) * 60 + self.wn.options.time.pattern_timestep = float(self.timestep) * 60 + self.wn.options.time.report_timestep = float(self.timestep) * 60 + + # 加载区域映射 + if isinstance(area_map, str): + self.area_map_df = self._load_area_map(area_map) + elif isinstance(area_map, dict): + self.area_map_df = self._normalize_area_map_df( + pd.DataFrame(list(area_map.items()), columns=["ID", "Area"]) + ) + else: + raise ValueError("area_map 必须是 CSV 文件路径或字典。") + + self.area_ids = sorted(self.area_map_df["Area"].unique()) + self.num_areas = len(self.area_ids) + + # 按区域对节点进行预分类,以便更快查找 + self.nodes_by_area = { + area: self.area_map_df[self.area_map_df["Area"] == area]["ID"].tolist() + for area in self.area_ids + } + + def _load_area_map(self, path: str) -> pd.DataFrame: + """加载并验证节点-区域映射文件。""" + df = pd.read_csv(path, dtype={"ID": str, "Area": str}) + return self._normalize_area_map_df(df) + + def run_identification( + self, + observed_pressure_data: Union[ + str, pd.DataFrame, Dict[str, List[Any]], List[Dict[str, Any]] + ], + output_dir: str = "Results", + pop_size: int = 50, + max_gen: int = 100, + output_flow_unit: str = "m3/s", + save_result: bool = True, + ftol: float = 1e-3, + ftol_period: int = 15, + n_workers: int = DEFAULT_N_WORKERS, + ): + """ + 运行遗传算法以识别漏损分布。 + + 参数: + observed_pressure_data: 包含 SCADA 压力数据的 CSV 文件路径或 DataFrame/字典列表数据。 + output_dir: 结果保存目录。 + pop_size: GA 的种群大小。 + max_gen: GA 的最大代数。 + output_flow_unit: 输出漏损流量的单位。 + save_result: 是否保存识别结果到本地 CSV。 + ftol: 目标值收敛容差(连续 ftol_period 代改善 < ftol 则停止)。 + ftol_period: 收敛检测的窗口代数。 + n_workers: 并行工作进程数(1=串行,>1=并行评估)。 + """ + if save_result: + os.makedirs(output_dir, exist_ok=True) + + # 加载观测数据 + if isinstance(observed_pressure_data, str): + obs_df = pd.read_csv(observed_pressure_data) + observed_name = os.path.basename(observed_pressure_data) + elif isinstance(observed_pressure_data, pd.DataFrame): + obs_df = observed_pressure_data.copy() + observed_name = "observed_pressure.csv" + else: + obs_df = pd.DataFrame(observed_pressure_data) + observed_name = "observed_pressure.csv" + + # 准备 pymoo 问题实例 + problem = LeakageProblem( + self.wn, + self.nodes_by_area, + self.area_ids, + self.sensor_nodes, + obs_df, + q_sum=self.q_sum, + n_workers=n_workers, + inp_path=os.path.abspath(self.inp_path), + ) + + # 配置 pymoo GA 算法 + n_var = self.num_areas + algorithm = GA( + pop_size=pop_size, + crossover=SBX(prob=0.9, eta=15), + mutation=PM(prob=1.0 / max(1, n_var), eta=20), + eliminate_duplicates=False, + ) + + # 终止条件:收敛检测 + 最大代数 + termination = DefaultSingleObjectiveTermination( + ftol=ftol, + period=ftol_period, + n_max_gen=max_gen, + ) + + # 回调:记录每代信息 + callback = _ProgressCallback() + + t0 = time.time() + try: + res = pymoo_minimize( + problem, + algorithm, + termination, + seed=42, + verbose=True, + callback=callback, + ) + finally: + problem.close() + elapsed = time.time() - t0 + + # 提取最优解 + best_ind = res.X # 最优个体(漏损比例原始值) + best_obj = float(res.F[0]) + + # 输出终止信息 + print(f"\n优化完成。耗时: {elapsed:.1f}s") + print(f"总代数: {res.algorithm.n_gen}, 总评估次数: {problem._eval_count}") + print(f"最佳目标值: {best_obj:.6f}") + + # 保存到文件 + effective_ratio_map = self._effective_area_ratios( + best_ind, + self.area_ids, + self.nodes_by_area, + allocatable_counts=problem.allocatable_counts, + ) + normalized_ratios = [ + effective_ratio_map.get(area_id, 0.0) for area_id in self.area_ids + ] + leakage_flow_m3s = [ratio * self.q_sum for ratio in normalized_ratios] + leakage_flow_output = [ + self._flow_from_m3s(value_m3s, output_flow_unit) + for value_m3s in leakage_flow_m3s + ] + + result_df = pd.DataFrame( + { + "Area": self.area_ids, + "LeakageRatioRaw": best_ind, + "LeakageRatio": normalized_ratios, + "LeakageFlow_m3_per_s": leakage_flow_m3s, + f"LeakageFlow_{output_flow_unit.replace('/', '_per_')}": leakage_flow_output, + } + ) + result_path = None + if save_result: + result_path = os.path.join( + output_dir, f"identified_leakage_{observed_name}" + ) + result_df.to_csv(result_path, index=False) + print(f"结果已保存至 {result_path}") + result_df.attrs["result_path"] = result_path + return result_df + + +class _ProgressCallback(Callback): + """每代回调:记录进度。""" + + def __init__(self): + super().__init__() + self.gen_times = [] + self._t_last = None + + def notify(self, algorithm): + now = time.time() + if self._t_last is not None: + self.gen_times.append(now - self._t_last) + self._t_last = now + + +class LeakageProblem(Problem): + """pymoo 批量评估问题定义。 + + 搜索空间:n 维 [0, 1] 实数 -> 通过 _effective_area_ratios 归一化到单纯形。 + 目标:模拟压力与观测压力之间的归一化误差范数。 + 无显式约束(sum=1 由归一化自动保证)。 + """ + + def __init__( + self, + wn, + nodes_by_area, + area_ids, + sensor_nodes, + observed_data, + q_sum: float = 0.2, + n_workers: int = DEFAULT_N_WORKERS, + inp_path: str | None = None, + ): + n_var = len(area_ids) + + super().__init__( + n_var=n_var, + n_obj=1, + n_ieq_constr=0, + xl=np.zeros(n_var), + xu=np.ones(n_var), + ) + + self.wn = wn + self.nodes_by_area = nodes_by_area + self.area_ids = area_ids + self.sensor_nodes = sensor_nodes + self.q_sum = q_sum + self.n_workers = max(1, int(n_workers)) + self.inp_path = inp_path + + # 预处理观测数据以匹配模拟格式 + try: + missing_sensors = [ + s for s in self.sensor_nodes if s not in observed_data.columns + ] + if not missing_sensors: + self.obs_matrix = observed_data[self.sensor_nodes].values + else: + self.obs_matrix = observed_data.values[:, : len(self.sensor_nodes)] + except Exception: + self.obs_matrix = observed_data.values[:, : len(self.sensor_nodes)] + + duration_sec = float(self.wn.options.time.duration) + step_sec = float(self.wn.options.time.hydraulic_timestep) + if step_sec > 0: + max_steps = int(duration_sec / step_sec) + 1 + self.obs_matrix = self.obs_matrix[:max_steps, :] + + # 预先缓存每个区域的需水对象,减少每次适应度计算的节点查找 + self.demand_objs_by_area = {} + for area_id in self.area_ids: + demand_objs = [] + for node_name in self.nodes_by_area.get(area_id, []): + if node_name not in self.wn.node_name_list: + continue + node = self.wn.get_node(node_name) + if ( + hasattr(node, "demand_timeseries_list") + and len(node.demand_timeseries_list) > 0 + ): + demand_objs.append(node.demand_timeseries_list[0]) + self.demand_objs_by_area[area_id] = demand_objs + + self.allocatable_counts = { + area_id: len(self.demand_objs_by_area.get(area_id, [])) + for area_id in self.area_ids + } + if not any(count > 0 for count in self.allocatable_counts.values()): + raise ValueError("没有可分配漏损的有效分区,无法满足漏损总量约束。") + + # 评估计数器(诊断用) + self._eval_count = 0 + self._pool = None + if self.n_workers > 1: + if not self.inp_path: + raise ValueError("并行评估需要提供 inp_path。") + duration_sec = float(self.wn.options.time.duration) + timestep_sec = float(self.wn.options.time.hydraulic_timestep) + self._pool = Pool( + processes=self.n_workers, + initializer=_worker_init, + initargs=( + self.inp_path, + list(self.sensor_nodes), + list(self.area_ids), + {k: list(v) for k, v in self.nodes_by_area.items()}, + self.obs_matrix.copy(), + self.q_sum, + duration_sec, + timestep_sec, + ), + ) + + def _evaluate(self, X, out, *args, **kwargs): + """批量评估种群。 + + X: 形状 (pop_size, n_var) 的决策变量矩阵。 + """ + n_pop = X.shape[0] + self._eval_count += n_pop + + if self._pool is not None: + results = self._pool.map(_worker_evaluate, [X[i] for i in range(n_pop)]) + out["F"] = np.array(results, dtype=float).reshape(-1, 1) + return + + F = np.zeros((n_pop, 1)) + for i in range(n_pop): + F[i, 0] = self._evaluate_single(X[i]) + out["F"] = F + + def _evaluate_single(self, x): + """评估单个个体,返回归一化误差范数。""" + leak_ratios = x + + # 将漏损分布归一化 + effective_ratio_map = LeakageIdentifier._effective_area_ratios( + leak_ratios, + self.area_ids, + self.nodes_by_area, + allocatable_counts=self.allocatable_counts, + ) + + # 跟踪修改以便稍后恢复 + modifications = [] + + for j, area_id in enumerate(self.area_ids): + ratio = effective_ratio_map.get(area_id, 0.0) + if ratio <= 0: + continue + + demand_objs = self.demand_objs_by_area.get(area_id, []) + if not demand_objs: + continue + + per_node_leak = self.q_sum * ratio / len(demand_objs) + + for demand_obj in demand_objs: + original_val = demand_obj.base_value + demand_obj.base_value = original_val + per_node_leak + modifications.append((demand_obj, original_val)) + + # 结果保存在根目录的temp/leakage文件夹中 + temp_dir = os.path.abspath(os.path.join("temp", "leakage")) + os.makedirs(temp_dir, exist_ok=True) + prefix = os.path.join(temp_dir, f"temp_{os.getpid()}") + + try: + sim = wntr.sim.EpanetSimulator(self.wn) + results = sim.run_sim(file_prefix=prefix) + sim_pressure = results.node["pressure"].loc[:, self.sensor_nodes] + + n_steps = min(sim_pressure.shape[0], self.obs_matrix.shape[0]) + sim_vals = sim_pressure.values[:n_steps, :] + obs_vals = self.obs_matrix[:n_steps, :] + + diff = sim_vals - obs_vals + + # 按行最大值归一化 + row_max = np.max(np.abs(diff), axis=1, keepdims=True) + row_max[row_max == 0] = 1.0 # 防止除以零 + + normalized_diff = diff / row_max + + # 目标:归一化差值矩阵的 2-范数 + return float(np.linalg.norm(normalized_diff)) + + except Exception: + return 1e9 + + finally: + for demand_obj, original_val in modifications: + demand_obj.base_value = original_val + + _cleanup_temp_files(prefix) + + def close(self) -> None: + if self._pool is not None: + self._pool.close() + self._pool.join() + self._pool = None + + +def main() -> int: + parser = argparse.ArgumentParser(description="漏损区域识别") + parser.add_argument("--inp", required=True, help=".inp 文件路径") + parser.add_argument("--map", help="节点-区域映射 CSV 路径") + parser.add_argument("--scada", help="SCADA 压力 CSV 路径 (观测数据)") + parser.add_argument("--sensors", help="传感器节点 ID 列表 (逗号分隔)") + parser.add_argument("--output", default="Results", help="输出目录") + + parser.add_argument("--pop_size", type=int, default=50, help="种群大小") + parser.add_argument("--max_gen", type=int, default=100, help="最大代数") + parser.add_argument("--duration", type=float, default=24, help="模拟时长(小时)") + parser.add_argument("--q_sum", type=float, default=0.241, help="总漏损流量") + parser.add_argument( + "--q_sum_unit", + default="m3/s", + choices=list(LeakageIdentifier.FLOW_UNIT_TO_M3S.keys()), + help="q_sum 输入单位(建议与现场习惯一致,内部统一换算为 m3/s)", + ) + + args = parser.parse_args() + + if not args.map or not args.scada or not args.sensors: + parser.error("--map、--scada、--sensors 为必填") + + q_sum_m3s = LeakageIdentifier._flow_to_m3s(args.q_sum, args.q_sum_unit) + + sensors = [sensor.strip() for sensor in args.sensors.split(",") if sensor.strip()] + identifier = LeakageIdentifier( + args.inp, sensors, args.map, duration=args.duration, q_sum=q_sum_m3s + ) + + identifier.run_identification( + args.scada, + args.output, + pop_size=args.pop_size, + max_gen=args.max_gen, + output_flow_unit=args.q_sum_unit, + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/app/algorithms/sensor/__init__.py b/app/algorithms/sensor/__init__.py new file mode 100644 index 0000000..d6c1a48 --- /dev/null +++ b/app/algorithms/sensor/__init__.py @@ -0,0 +1,91 @@ +import psycopg + +from app.algorithms.sensor import kmeans as kmeans_sensor +from app.algorithms.sensor import sensitivity +from app.core.config import get_pgconn_string +from app.services.tjnetwork import dump_inp + + +def pressure_sensor_placement_sensitivity( + name: str, scheme_name: str, sensor_number: int, min_diameter: int, username: str +) -> None: + """ + 基于改进灵敏度法进行压力监测点优化布置 + :param name: 数据库名称 + :param scheme_name: 监测优化布置方案名称 + :param sensor_number: 传感器数目 + :param min_diameter: 最小管径 + :param username: 用户名 + :return: + """ + sensor_location = sensitivity.get_ID( + name=name, sensor_num=sensor_number, min_diameter=min_diameter + ) + try: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + sql = """ + INSERT INTO sensor_placement (scheme_name, sensor_number, min_diameter, username, sensor_location) + VALUES (%s, %s, %s, %s, %s) + """ + + cur.execute( + sql, + ( + scheme_name, + sensor_number, + min_diameter, + username, + sensor_location, + ), + ) + conn.commit() + print("方案信息存储成功!") + except Exception as e: + print(f"存储方案信息时出错:{e}") + + +# 2025/08/21 +# 基于kmeans聚类法进行压力监测点优化布置 +def pressure_sensor_placement_kmeans( + name: str, scheme_name: str, sensor_number: int, min_diameter: int, username: str +) -> None: + """ + 基于聚类法进行压力监测点优化布置 + :param name: 数据库名称(注意,此处数据库名称也是inp文件名称,inp文件与pg库名要一样) + :param scheme_name: 监测优化布置方案名称 + :param sensor_number: 传感器数目 + :param min_diameter: 最小管径 + :param username: 用户名 + :return: + """ + # dump_inp + inp_name = f"./db_inp/{name}.db.inp" + dump_inp(name, inp_name, "2") + sensor_location = kmeans_sensor.kmeans_sensor_placement( + name=name, sensor_num=sensor_number, min_diameter=min_diameter + ) + try: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + sql = """ + INSERT INTO sensor_placement (scheme_name, sensor_number, min_diameter, username, sensor_location) + VALUES (%s, %s, %s, %s, %s) + """ + + cur.execute( + sql, + ( + scheme_name, + sensor_number, + min_diameter, + username, + sensor_location, + ), + ) + conn.commit() + print("方案信息存储成功!") + except Exception as e: + print(f"存储方案信息时出错:{e}") diff --git a/app/algorithms/sensor/kmeans.py b/app/algorithms/sensor/kmeans.py new file mode 100644 index 0000000..e30c70e --- /dev/null +++ b/app/algorithms/sensor/kmeans.py @@ -0,0 +1,109 @@ +import wntr +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import sklearn.cluster +import os + + + +class QD_KMeans(object): + def __init__(self, wn, num_monitors): + # self.inp = inp + self.cluster_num = num_monitors # 聚类中心个数,也即测压点个数 + self.wn=wn + self.monitor_nodes = [] + self.coords = [] + self.junction_nodes = {} # Added missing initialization + + + def get_junctions_coordinates(self): + + for junction_name in self.wn.junction_name_list: + junction = self.wn.get_node(junction_name) + self.junction_nodes[junction_name] = junction.coordinates + self.coords.append(junction.coordinates ) + + # print(f"Total junctions: {self.junction_coordinates}") + + def select_monitoring_points(self): + if not self.coords: # Add check if coordinates are collected + self.get_junctions_coordinates() + coords = np.array(self.coords) + coords_normalized = (coords - coords.min(axis=0)) / (coords.max(axis=0) - coords.min(axis=0)) + kmeans = sklearn.cluster.KMeans(n_clusters= self.cluster_num, random_state=42) + kmeans.fit(coords_normalized) + + for center in kmeans.cluster_centers_: + distances = np.sum((coords_normalized - center) ** 2, axis=1) + nearest_node = self.wn.junction_name_list[np.argmin(distances)] + self.monitor_nodes.append(nearest_node) + + return self.monitor_nodes + + + def visualize_network(self): + """Visualize network with monitoring points""" + ax=wntr.graphics.plot_network(self.wn, + node_attribute=self.monitor_nodes, + node_size=30, + title='Optimal sensor') + plt.show() + + + + +def kmeans_sensor_placement(name: str, sensor_num: int, min_diameter: int) -> list: + inp_name = f'./db_inp/{name}.db.inp' + wn= wntr.network.WaterNetworkModel(inp_name) + wn_cluster=QD_KMeans(wn, sensor_num) + + # Select monitoring pointse + sensor_ids= wn_cluster.select_monitoring_points() + + # wn_cluster.visualize_network() + + return sensor_ids + + + +if __name__ == "__main__": + #sensorindex = get_ID(name='suzhouhe_2024_cloud_0817', sensor_num=30, min_diameter=500) + sensorindex = kmeans_sensor_placement(name='szh', sensor_num=50, min_diameter=300) + print(sensorindex) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sensitivity.py b/app/algorithms/sensor/sensitivity.py similarity index 99% rename from sensitivity.py rename to app/algorithms/sensor/sensitivity.py index 68e7068..1f19925 100644 --- a/sensitivity.py +++ b/app/algorithms/sensor/sensitivity.py @@ -11,7 +11,6 @@ from sklearn.cluster import KMeans from wntr.epanet.toolkit import EpanetException from numpy.linalg import slogdet import random -from tjnetwork import * from matplotlib.lines import Line2D from sklearn.cluster import SpectralClustering import libpysal as ps @@ -19,7 +18,7 @@ from spopt.region import Skater from shapely.geometry import Point import geopandas as gpd from sklearn.metrics import pairwise_distances -import project_info +import app.services.project_info as project_info # 2025/03/12 # Step1: 获取节点坐标 diff --git a/app/algorithms/simulation/__init__.py b/app/algorithms/simulation/__init__.py new file mode 100644 index 0000000..b8e0fa6 --- /dev/null +++ b/app/algorithms/simulation/__init__.py @@ -0,0 +1,19 @@ +from app.algorithms.simulation.scenarios import ( + convert_to_local_unit, + burst_analysis, + valve_close_analysis, + flushing_analysis, + contaminant_simulation, + age_analysis, + pressure_regulation, +) + +__all__ = [ + "convert_to_local_unit", + "burst_analysis", + "valve_close_analysis", + "flushing_analysis", + "contaminant_simulation", + "age_analysis", + "pressure_regulation", +] diff --git a/run_simulation.py b/app/algorithms/simulation/runner.py similarity index 99% rename from run_simulation.py rename to app/algorithms/simulation/runner.py index e118aba..004caba 100644 --- a/run_simulation.py +++ b/app/algorithms/simulation/runner.py @@ -1,6 +1,26 @@ import numpy as np -from tjnetwork import * -from api.s36_wda_cal import * +from app.services.tjnetwork import ( + ChangeSet, + close_project, + copy_project, + delete_project, + get_pattern, + get_patterns, + get_pump, + get_reservoir, + get_status, + get_tank, + get_time, + have_project, + is_project_open, + open_project, + read_all, + run_project, + set_pattern, + set_status, + set_tank, + set_time, +) # from get_real_status import * from datetime import datetime,timedelta from math import modf @@ -8,7 +28,7 @@ import json import pytz import requests import time -import project_info +import app.services.project_info as project_info url_path = 'http://10.101.15.16:9000/loong' # 内网 # url_path = 'http://183.64.62.100:9057/loong' # 外网 diff --git a/app/algorithms/simulation/scenarios.py b/app/algorithms/simulation/scenarios.py new file mode 100644 index 0000000..9db4ea7 --- /dev/null +++ b/app/algorithms/simulation/scenarios.py @@ -0,0 +1,771 @@ +import json +from datetime import datetime +from math import pi, sqrt + +import pytz + +import app.services.simulation as simulation +from app.algorithms.simulation.runner import ( + run_simulation_ex, + from_clock_to_seconds_2, +) +from app.infra.epanet.epanet import Output +from app.services.scheme_management import store_scheme_info +from app.services.tjnetwork import ( + ChangeSet, + OPTION_DEMAND_MODEL_PDA, + OPTION_QUALITY_CHEMICAL, + SOURCE_TYPE_SETPOINT, + add_pattern, + add_source, + close_project, + copy_project, + delete_project, + get_demand, + get_emitter, + get_node_links, + get_option, + get_pattern, + get_pipe, + get_source, + get_time, + have_project, + is_junction, + is_project_open, + open_project, + set_demand, + set_emitter, + set_option, + set_source, + set_time, +) + + +############################################################ +# burst analysis 01 +############################################################ +def convert_to_local_unit(proj: str, emitters: float) -> float: + open_project(proj) + proj_opt = get_option(proj) + str_unit = proj_opt.get("UNITS") + + if str_unit == "CMH": + return emitters * 3.6 + elif str_unit == "LPS": + return emitters + elif str_unit == "CMS": + return emitters / 1000.0 + elif str_unit == "MGD": + return emitters * 0.0438126 + + # Unknown unit: log and return original value + print(str_unit) + return emitters + + +def burst_analysis( + name: str, + modify_pattern_start_time: str, + burst_ID: list | str = None, + burst_size: list | float | int = None, + modify_total_duration: int = 900, + modify_fixed_pump_pattern: dict[str, list] = None, + modify_variable_pump_pattern: dict[str, list] = None, + modify_valve_opening: dict[str, float] = None, + scheme_name: str = None, +) -> None: + """ + 爆管模拟 + :param name: 模型名称,数据库中对应的名字 + :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + :param burst_ID: 爆管管道的ID,选取的是管道,单独传入一个爆管管道,可以是str或list,传入多个爆管管道是用list + :param burst_size: 爆管管道破裂的孔口面积,和burst_ID列表各位置的ID对应,以cm*cm计算 + :param modify_total_duration: 模拟总历时,秒 + :param modify_fixed_pump_pattern: dict中包含多个水泵模式,str为工频水泵的id,list为修改后的pattern + :param modify_variable_pump_pattern: dict中包含多个水泵模式,str为变频水泵的id,list为修改后的pattern + :param modify_valve_opening: dict中包含多个阀门开启度,str为阀门的id,float为修改后的阀门开启度 + :param scheme_name: 方案名称 + :return: + """ + scheme_detail: dict = { + "burst_ID": burst_ID, + "burst_size": burst_size, + "modify_total_duration": modify_total_duration, + "modify_fixed_pump_pattern": modify_fixed_pump_pattern, + "modify_variable_pump_pattern": modify_variable_pump_pattern, + "modify_valve_opening": modify_valve_opening, + } + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"burst_Anal_{name}" + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + simulation.run_simulation( + name=new_name, + simulation_type="manually_temporary", + modify_pattern_start_time=modify_pattern_start_time, + ) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + ##step 1 set the emitter coefficient of end node of busrt pipe + if isinstance(burst_ID, list): + if (burst_size is not None) and (type(burst_size) is not list): + return json.dumps("Type mismatch.") + # 转化为列表形式 + elif isinstance(burst_ID, str): + burst_ID = [burst_ID] + if burst_size is not None: + if isinstance(burst_size, float) or isinstance(burst_size, int): + burst_size = [burst_size] + else: + return json.dumps("Type mismatch.") + else: + return json.dumps("Type mismatch.") + if burst_size is None: + burst_size = [-1] * len(burst_ID) + elif len(burst_size) < len(burst_ID): + burst_size += [-1] * (len(burst_ID) - len(burst_size)) + elif len(burst_size) > len(burst_ID): + # burst_size = burst_size[:len(burst_ID)] + return json.dumps("Length mismatch.") + for burst_ID_, burst_size_ in zip(burst_ID, burst_size): + pipe = get_pipe(new_name, burst_ID_) + str_start_node = pipe["node1"] + str_end_node = pipe["node2"] + d_pipe = pipe["diameter"] / 1000.0 + if burst_size_ <= 0: + burst_size_ = 3.14 * d_pipe * d_pipe / 4 / 8 + else: + burst_size_ = burst_size_ / 10000 + emitter_coeff = ( + 0.65 * burst_size_ * sqrt(19.6) * 1000 + ) # 1/8开口面积作为coeff,单位 L/S + emitter_coeff = convert_to_local_unit(new_name, emitter_coeff) + emitter_node = "" + if is_junction(new_name, str_end_node): + emitter_node = str_end_node + elif is_junction(new_name, str_start_node): + emitter_node = str_start_node + old_emitter = get_emitter(new_name, emitter_node) + if old_emitter != None: + old_emitter["coefficient"] = emitter_coeff # 爆管的emitter coefficient设置 + else: + old_emitter = {"junction": emitter_node, "coefficient": emitter_coeff} + new_emitter = ChangeSet() + new_emitter.append(old_emitter) + set_emitter(new_name, new_emitter) + # step 2. run simulation + # 涉及关阀计算,可能导致关阀后仍有流量,改为压力驱动PDA + options = get_option(new_name) + options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA + options["REQUIRED PRESSURE"] = "10.0000" + cs_options = ChangeSet() + cs_options.append(options) + set_option(new_name, cs_options) + # valve_control = None + # if modify_valve_opening is not None: + # valve_control = {} + # for valve in modify_valve_opening: + # valve_control[valve] = {'status': 'CLOSED'} + # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, + # end_datetime=modify_pattern_start_time, + # modify_total_duration=modify_total_duration, + # modify_pump_pattern=modify_pump_pattern, + # valve_control=valve_control, + # downloading_prohibition=True) + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + modify_fixed_pump_pattern=modify_fixed_pump_pattern, + modify_variable_pump_pattern=modify_variable_pump_pattern, + modify_valve_opening=modify_valve_opening, + scheme_type="burst_analysis", + scheme_name=scheme_name, + ) + # step 3. restore the base model status + # execute_undo(name) #有疑惑 + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # 存储方案信息到 PG 数据库 + store_scheme_info( + name=name, + scheme_name=scheme_name, + scheme_type="burst_analysis", + username="admin", + scheme_start_time=modify_pattern_start_time, + scheme_detail=scheme_detail, + ) + + +############################################################ +# valve closing analysis 02 +############################################################ +def valve_close_analysis( + name: str, + modify_pattern_start_time: str, + modify_total_duration: int = 900, + modify_valve_opening: dict[str, float] = None, + scheme_name: str = None, +) -> None: + """ + 关阀模拟 + :param name: 模型名称,数据库中对应的名字 + :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + :param modify_total_duration: 模拟总历时,秒 + :param modify_valve_opening: dict中包含多个阀门开启度,str为阀门的id,float为修改后的阀门开启度 + :param scheme_name: 方案名称 + :return: + """ + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"valve_close_Anal_{name}" + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + # step 1. change the valves status to 'closed' + # for valve in valves: + # if not is_valve(new_name,valve): + # result='ID:{}is not a valve type'.format(valve) + # return result + # cs=ChangeSet() + # status=get_status(new_name,valve) + # status['status']='CLOSED' + # cs.append(status) + # set_status(new_name,cs) + # step 2. run simulation + # 涉及关阀计算,可能导致关阀后仍有流量,改为压力驱动PDA + options = get_option(new_name) + options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA + options["REQUIRED PRESSURE"] = "20.0000" + cs_options = ChangeSet() + cs_options.append(options) + set_option(new_name, cs_options) + # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time, modify_total_duration, + # downloading_prohibition=True) + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + modify_valve_opening=modify_valve_opening, + scheme_type="valve_close_Analysis", + scheme_name=scheme_name, + ) + # step 3. restore the base model + # for valve in valves: + # execute_undo(name) + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # return result + + +############################################################ +# flushing analysis 03 +# Pipe_Flushing_Analysis(prj_name,date_time, Valve_id_list, Drainage_Node_Id, Flushing_flow[opt], Flushing_duration[opt])->out_file:string +############################################################ +def flushing_analysis( + name: str, + modify_pattern_start_time: str, + modify_total_duration: int = 900, + modify_valve_opening: dict[str, float] = None, + drainage_node_ID: str = None, + flushing_flow: float = 0, + scheme_name: str = None, +) -> None: + """ + 管道冲洗模拟 + :param name: 模型名称,数据库中对应的名字 + :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + :param modify_total_duration: 模拟总历时,秒 + :param modify_valve_opening: dict中包含多个阀门开启度,str为阀门的id,float为修改后的阀门开启度 + :param drainage_node_ID: 冲洗排放口所在节点ID + :param flushing_flow: 冲洗水量,传入参数单位为m3/h + :param scheme_name: 方案名称 + :return: + """ + scheme_detail: dict = { + "duration": modify_total_duration, + "valve_opening": modify_valve_opening, + "drainage_node_ID": drainage_node_ID, + "flushing_flow": flushing_flow, + } + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"flushing_Anal_{name}" + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # if is_project_open(name): + # close_project(name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + if not is_junction(new_name, drainage_node_ID): + return "Wrong Drainage node type" + # step 1. change the valves status to 'closed' + # for valve, valve_k in zip(valves, valves_k): + # cs=ChangeSet() + # status=get_status(new_name,valve) + # # status['status']='CLOSED' + # if valve_k == 0: + # status['status'] = 'CLOSED' + # elif valve_k < 1: + # status['status'] = 'OPEN' + # status['setting'] = 0.1036 * pow(valve_k, -3.105) + # cs.append(status) + # set_status(new_name,cs) + options = get_option(new_name) + units = options["UNITS"] + # step 2. set the emitter coefficient of drainage node or add flush flow to the drainage node + # 新建 pattern + time_option = get_time(new_name) + hydraulic_step = time_option["HYDRAULIC TIMESTEP"] + secs = from_clock_to_seconds_2(hydraulic_step) + cs_pattern = ChangeSet() + pt = {} + factors = [] + tmp_duration = modify_total_duration + while tmp_duration > 0: + factors.append(1.0) + tmp_duration = tmp_duration - secs + pt["id"] = "flushing_pt" + pt["factors"] = factors + cs_pattern.append(pt) + add_pattern(new_name, cs_pattern) + # 为 emitter_demand 添加新的 pattern + emitter_demand = get_demand(new_name, drainage_node_ID) + cs = ChangeSet() + if flushing_flow > 0: + if units == "LPS": + emitter_demand["demands"].append( + { + "demand": flushing_flow / 3.6, + "pattern": "flushing_pt", + "category": None, + } + ) + elif units == "CMH": + emitter_demand["demands"].append( + {"demand": flushing_flow, "pattern": "flushing_pt", "category": None} + ) + cs.append(emitter_demand) + set_demand(new_name, cs) + else: + pipes = get_node_links(new_name, drainage_node_ID) + flush_diameter = 50 + for pipe in pipes: + d = get_pipe(new_name, pipe)["diameter"] + if flush_diameter < d: + flush_diameter = d + flush_diameter /= 1000 + emitter_coeff = ( + 0.65 * 3.14 * (flush_diameter * flush_diameter / 4) * sqrt(19.6) * 1000 + ) # 全开口面积作为coeff + + old_emitter = get_emitter(new_name, drainage_node_ID) + if old_emitter != None: + old_emitter["coefficient"] = emitter_coeff # 爆管的emitter coefficient设置 + else: + old_emitter = {"junction": drainage_node_ID, "coefficient": emitter_coeff} + new_emitter = ChangeSet() + new_emitter.append(old_emitter) + set_emitter(new_name, new_emitter) + # step 3. run simulation + # 涉及关阀计算,可能导致关阀后仍有流量,改为压力驱动PDA + options = get_option(new_name) + options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA + options["REQUIRED PRESSURE"] = "20.0000" + cs_options = ChangeSet() + cs_options.append(options) + set_option(new_name, cs_options) + # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time, modify_total_duration, + # downloading_prohibition=True) + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + modify_valve_opening=modify_valve_opening, + scheme_type="flushing_analysis", + scheme_name=scheme_name, + ) + # step 4. restore the base model + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # return result + # 存储方案信息到 PG 数据库 + store_scheme_info( + name=name, + scheme_name=scheme_name, + scheme_type="flushing_analysis", + username="admin", + scheme_start_time=modify_pattern_start_time, + scheme_detail=scheme_detail, + ) + + +############################################################ +# Contaminant simulation 04 +# +############################################################ +def contaminant_simulation( + name: str, + modify_pattern_start_time: str, # 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + modify_total_duration: int, # 模拟总历时,秒 + source: str, # 污染源节点ID + concentration: float, # 污染源浓度,单位mg/L + scheme_name: str = None, + source_pattern: str = None, # 污染源时间变化模式名称 +) -> None: + """ + 污染模拟 + :param name: 模型名称,数据库中对应的名字 + :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + :param modify_total_duration: 模拟总历时,秒 + :param source: 污染源所在的节点ID + :param concentration: 污染源位置处的浓度,单位mg/L。默认的污染模拟setting为SOURCE_TYPE_CONCEN(改为SOURCE_TYPE_SETPOINT) + :param source_pattern: 污染源的时间变化模式,若不传入则默认以恒定浓度持续模拟,时间长度等于duration; + 若传入,则格式为{1.0,0.5,1.1}等系数列表pattern_step模拟等于模型的hydraulic time step + :param scheme_name: 方案名称 + :return: + """ + scheme_detail: dict = { + "source": source, + "concentration": concentration, + "duration": modify_total_duration, + "pattern": source_pattern, + } + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"contaminant_Sim_{name}" + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # if is_project_open(name): + # close_project(name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + dic_time = get_time(new_name) + dic_time["QUALITY TIMESTEP"] = "0:05:00" + cs = ChangeSet() + cs.operations.append(dic_time) + set_time(new_name, cs) # set QUALITY TIMESTEP + time_option = get_time(new_name) + hydraulic_step = time_option["HYDRAULIC TIMESTEP"] + secs = from_clock_to_seconds_2(hydraulic_step) + operation_step = 0 + # step 1. set duration + if modify_total_duration == None: + modify_total_duration = secs + # step 2. set pattern + if source_pattern != None: + pt = get_pattern(new_name, source_pattern) + if len(pt) == 0: + str_response = str("cant find source_pattern") + return str_response + else: + cs_pattern = ChangeSet() + pt = {} + factors = [] + tmp_duration = modify_total_duration + while tmp_duration > 0: + factors.append(1.0) + tmp_duration = tmp_duration - secs + pt["id"] = "contam_pt" + pt["factors"] = factors + cs_pattern.append(pt) + add_pattern(new_name, cs_pattern) + operation_step += 1 + # step 3. set source/initial quality + # source quality + cs_source = ChangeSet() + source_schema = { + "node": source, + "s_type": SOURCE_TYPE_SETPOINT, + "strength": concentration, + "pattern": pt["id"], + } + cs_source.append(source_schema) + source_node = get_source(new_name, source) + if len(source_node) == 0: + add_source(new_name, cs_source) + else: + set_source(new_name, cs_source) + dict_demand = get_demand(new_name, source) + for demands in dict_demand["demands"]: + dict_demand["demands"][dict_demand["demands"].index(demands)]["demand"] = -1 + dict_demand["demands"][dict_demand["demands"].index(demands)]["pattern"] = None + cs = ChangeSet() + cs.append(dict_demand) + set_demand(new_name, cs) # set inflow node + # # initial quality + # dict_quality = get_quality(new_name, source) + # dict_quality['quality'] = concentration + # cs = ChangeSet() + # cs.append(dict_quality) + # set_quality(new_name, cs) + operation_step += 1 + # step 4 set option of quality to chemical + opt = get_option(new_name) + opt["QUALITY"] = OPTION_QUALITY_CHEMICAL + cs_option = ChangeSet() + cs_option.append(opt) + set_option(new_name, cs_option) + operation_step += 1 + # step 5. run simulation + # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time, modify_total_duration, + # downloading_prohibition=True) + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + scheme_type="contaminant_analysis", + scheme_name=scheme_name, + ) + + # for i in range(1,operation_step): + # execute_undo(name) + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # 存储方案信息到 PG 数据库 + store_scheme_info( + name=name, + scheme_name=scheme_name, + scheme_type="contaminant_analysis", + username="admin", + scheme_start_time=modify_pattern_start_time, + scheme_detail=scheme_detail, + ) + + +############################################################ +# age analysis 05 ***水龄模拟目前还没和实时模拟打通,不确定是否需要,先不要使用*** +############################################################ + + +def age_analysis( + name: str, modify_pattern_start_time: str, modify_total_duration: int = 900 +) -> None: + """ + 水龄模拟 + :param name: 模型名称,数据库中对应的名字 + :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + :param modify_total_duration: 模拟总历时,秒 + :return: + """ + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"age_Anal_{name}" + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # if is_project_open(name): + # close_project(name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + # step 1. run simulation + + result = run_simulation_ex( + new_name, + "realtime", + modify_pattern_start_time, + modify_total_duration, + downloading_prohibition=True, + ) + # step 2. restore the base model status + # execute_undo(name) #有疑惑 + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + output = Output("./temp/{}.db.out".format(new_name)) + # element_name = output.element_name() + # node_name = element_name['nodes'] + # link_name = element_name['links'] + nodes_age = [] + node_result = output.node_results() + for node in node_result: + nodes_age.append(node["result"][-1]["quality"]) + links_age = [] + link_result = output.link_results() + for link in link_result: + links_age.append(link["result"][-1]["quality"]) + age_result = {"nodes": nodes_age, "links": links_age} + # age_result = {'nodes': nodes_age, 'links': links_age, 'nodeIDs': node_name, 'linkIDs': link_name} + return json.dumps(age_result) + + +############################################################ +# pressure regulation 06 +############################################################ + + +def pressure_regulation( + name: str, + modify_pattern_start_time: str, + modify_total_duration: int = 900, + modify_tank_initial_level: dict[str, float] = None, + modify_fixed_pump_pattern: dict[str, list] = None, + modify_variable_pump_pattern: dict[str, list] = None, + scheme_name: str = None, +) -> None: + """ + 区域调压模拟,用来模拟未来15分钟内,开关水泵对区域压力的影响 + :param name: 模型名称,数据库中对应的名字 + :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + :param modify_total_duration: 模拟总历时,秒 + :param modify_tank_initial_level: dict中包含多个水塔,str为水塔的id,float为修改后的initial_level + :param modify_fixed_pump_pattern: dict中包含多个水泵模式,str为工频水泵的id,list为修改后的pattern + :param modify_variable_pump_pattern: dict中包含多个水泵模式,str为变频水泵的id,list为修改后的pattern + :param scheme_name: 模拟方案名称 + :return: + """ + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"pressure_regulation_{name}" + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # if is_project_open(name): + # close_project(name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + # 全部关泵后,压力计算不合理,改为压力驱动PDA + options = get_option(new_name) + options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA + options["REQUIRED PRESSURE"] = "15.0000" + cs_options = ChangeSet() + cs_options.append(options) + set_option(new_name, cs_options) + # result = run_simulation_ex(name=new_name, + # simulation_type='realtime', + # start_datetime=start_datetime, + # duration=900, + # pump_control=pump_control, + # tank_initial_level_control=tank_initial_level_control, + # downloading_prohibition=True) + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + modify_tank_initial_level=modify_tank_initial_level, + modify_fixed_pump_pattern=modify_fixed_pump_pattern, + modify_variable_pump_pattern=modify_variable_pump_pattern, + scheme_type="pressure_regulation", + scheme_name=scheme_name, + ) + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # return result diff --git a/app/api/__init__.py b/app/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/__init__.py b/app/api/v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/endpoints/__init__.py b/app/api/v1/endpoints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/endpoints/audit.py b/app/api/v1/endpoints/audit.py new file mode 100644 index 0000000..974d5e4 --- /dev/null +++ b/app/api/v1/endpoints/audit.py @@ -0,0 +1,104 @@ +""" +审计日志 API 接口 + +仅管理员可访问 +""" +from typing import List, Optional +from uuid import UUID +from datetime import datetime +from fastapi import APIRouter, Depends, Query +from app.domain.schemas.audit import AuditLogResponse +from app.infra.repositories.audit_repository import AuditRepository +from app.auth.metadata_dependencies import ( + get_current_metadata_admin, + get_current_metadata_user, +) +from app.infra.db.metadata.database import get_metadata_session +from sqlalchemy.ext.asyncio import AsyncSession + +router = APIRouter() + +async def get_audit_repository( + session: AsyncSession = Depends(get_metadata_session), +) -> AuditRepository: + """获取审计日志仓储""" + return AuditRepository(session) + +@router.get("/logs", response_model=List[AuditLogResponse]) +async def get_audit_logs( + user_id: Optional[UUID] = Query(None, description="按用户ID过滤"), + project_id: Optional[UUID] = Query(None, description="按项目ID过滤"), + action: Optional[str] = Query(None, description="按操作类型过滤"), + resource_type: Optional[str] = Query(None, description="按资源类型过滤"), + start_time: Optional[datetime] = Query(None, description="开始时间"), + end_time: Optional[datetime] = Query(None, description="结束时间"), + skip: int = Query(0, ge=0, description="跳过记录数"), + limit: int = Query(100, ge=1, le=1000, description="限制记录数"), + current_user=Depends(get_current_metadata_admin), + audit_repo: AuditRepository = Depends(get_audit_repository), +) -> List[AuditLogResponse]: + """ + 查询审计日志(仅管理员) + + 支持按用户、时间、操作类型等条件过滤 + """ + logs = await audit_repo.get_logs( + user_id=user_id, + project_id=project_id, + action=action, + resource_type=resource_type, + start_time=start_time, + end_time=end_time, + skip=skip, + limit=limit + ) + return logs + +@router.get("/logs/count") +async def get_audit_logs_count( + user_id: Optional[UUID] = Query(None, description="按用户ID过滤"), + project_id: Optional[UUID] = Query(None, description="按项目ID过滤"), + action: Optional[str] = Query(None, description="按操作类型过滤"), + resource_type: Optional[str] = Query(None, description="按资源类型过滤"), + start_time: Optional[datetime] = Query(None, description="开始时间"), + end_time: Optional[datetime] = Query(None, description="结束时间"), + current_user=Depends(get_current_metadata_admin), + audit_repo: AuditRepository = Depends(get_audit_repository), +) -> dict: + """ + 获取审计日志总数(仅管理员) + """ + count = await audit_repo.get_log_count( + user_id=user_id, + project_id=project_id, + action=action, + resource_type=resource_type, + start_time=start_time, + end_time=end_time + ) + return {"count": count} + +@router.get("/logs/my", response_model=List[AuditLogResponse]) +async def get_my_audit_logs( + action: Optional[str] = Query(None, description="按操作类型过滤"), + start_time: Optional[datetime] = Query(None, description="开始时间"), + end_time: Optional[datetime] = Query(None, description="结束时间"), + skip: int = Query(0, ge=0), + limit: int = Query(100, ge=1, le=1000), + current_user=Depends(get_current_metadata_user), + audit_repo: AuditRepository = Depends(get_audit_repository), +) -> List[AuditLogResponse]: + """ + 查询当前用户的审计日志 + + 普通用户只能查看自己的操作记录 + """ + logs = await audit_repo.get_logs( + user_id=current_user.id, + action=action, + start_time=start_time, + end_time=end_time, + skip=skip, + limit=limit + ) + return logs diff --git a/app/api/v1/endpoints/auth.py b/app/api/v1/endpoints/auth.py new file mode 100644 index 0000000..66b5cbd --- /dev/null +++ b/app/api/v1/endpoints/auth.py @@ -0,0 +1,186 @@ +from typing import Annotated +from datetime import timedelta +from fastapi import APIRouter, Depends, HTTPException, status +from fastapi.security import OAuth2PasswordRequestForm +from app.core.config import settings +from app.core.security import create_access_token, create_refresh_token, verify_password +from app.domain.schemas.user import UserCreate, UserResponse, UserLogin, Token +from app.infra.repositories.user_repository import UserRepository +from app.auth.dependencies import get_user_repository, get_current_active_user +from app.domain.schemas.user import UserInDB +import logging + +logger = logging.getLogger(__name__) + +router = APIRouter() + +@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED) +async def register( + user_data: UserCreate, + user_repo: UserRepository = Depends(get_user_repository) +) -> UserResponse: + """ + 用户注册 + + 创建新用户账号 + """ + # 检查用户名和邮箱是否已存在 + if await user_repo.user_exists(username=user_data.username): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Username already registered" + ) + + if await user_repo.user_exists(email=user_data.email): + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Email already registered" + ) + + # 创建用户 + try: + user = await user_repo.create_user(user_data) + if not user: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to create user" + ) + return UserResponse.model_validate(user) + except Exception as e: + logger.error(f"Error during user registration: {e}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Registration failed" + ) + +@router.post("/login", response_model=Token) +async def login( + form_data: Annotated[OAuth2PasswordRequestForm, Depends()], + user_repo: UserRepository = Depends(get_user_repository) +) -> Token: + """ + 用户登录(OAuth2 标准格式) + + 返回 JWT Access Token 和 Refresh Token + """ + # 验证用户(支持用户名或邮箱登录) + user = await user_repo.get_user_by_username(form_data.username) + if not user: + # 尝试用邮箱登录 + user = await user_repo.get_user_by_email(form_data.username) + + if not user or not verify_password(form_data.password, user.hashed_password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Bearer"}, + ) + + if not user.is_active: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Inactive user account" + ) + + # 生成 Token + access_token = create_access_token(subject=user.username) + refresh_token = create_refresh_token(subject=user.username) + + return Token( + access_token=access_token, + refresh_token=refresh_token, + token_type="bearer", + expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60 + ) + +@router.post("/login/simple", response_model=Token) +async def login_simple( + username: str, + password: str, + user_repo: UserRepository = Depends(get_user_repository) +) -> Token: + """ + 简化版登录接口(保持向后兼容) + + 直接使用 username 和 password 参数 + """ + # 验证用户 + user = await user_repo.get_user_by_username(username) + if not user: + user = await user_repo.get_user_by_email(username) + + if not user or not verify_password(password, user.hashed_password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password" + ) + + if not user.is_active: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Inactive user account" + ) + + # 生成 Token + access_token = create_access_token(subject=user.username) + refresh_token = create_refresh_token(subject=user.username) + + return Token( + access_token=access_token, + refresh_token=refresh_token, + token_type="bearer", + expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60 + ) + +@router.get("/me", response_model=UserResponse) +async def get_current_user_info( + current_user: UserInDB = Depends(get_current_active_user) +) -> UserResponse: + """ + 获取当前登录用户信息 + """ + return UserResponse.model_validate(current_user) + +@router.post("/refresh", response_model=Token) +async def refresh_token( + refresh_token: str, + user_repo: UserRepository = Depends(get_user_repository) +) -> Token: + """ + 刷新 Access Token + + 使用 Refresh Token 获取新的 Access Token + """ + from jose import jwt, JWTError + + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate refresh token", + headers={"WWW-Authenticate": "Bearer"}, + ) + + try: + payload = jwt.decode(refresh_token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) + username: str = payload.get("sub") + token_type: str = payload.get("type") + + if username is None or token_type != "refresh": + raise credentials_exception + + except JWTError: + raise credentials_exception + + # 验证用户仍然存在且激活 + user = await user_repo.get_user_by_username(username) + if not user or not user.is_active: + raise credentials_exception + + # 生成新的 Access Token + new_access_token = create_access_token(subject=user.username) + + return Token( + access_token=new_access_token, + refresh_token=refresh_token, # 保持原 refresh token + token_type="bearer", + expires_in=settings.ACCESS_TOKEN_EXPIRE_MINUTES * 60 + ) diff --git a/app/api/v1/endpoints/burst_detection.py b/app/api/v1/endpoints/burst_detection.py new file mode 100644 index 0000000..149343f --- /dev/null +++ b/app/api/v1/endpoints/burst_detection.py @@ -0,0 +1,71 @@ +from datetime import datetime +from typing import Any + +from fastapi import APIRouter, Depends, HTTPException +from pydantic import BaseModel, Field + +from app.auth.keycloak_dependencies import get_current_keycloak_username +from app.services.burst_detection import ( + get_burst_detection_scheme_detail, + list_burst_detection_schemes, + run_burst_detection, +) + +router = APIRouter() + + +class BurstDetectionRequest(BaseModel): + network: str + observed_pressure_data: ( + dict[str, list[Any]] | list[dict[str, Any]] | list[list[Any]] | None + ) = Field( + default=None, + description=( + "压力观测数据。支持列式字典 {sensor_id: [values,...]}、" + "逐时刻对象数组 [{sensor_id: value,...}, ...]、" + "或二维数组 [[t1_s1, t1_s2], [t2_s1, t2_s2], ...]。" + ), + ) + points_per_day: int = 1440 + mu: int = 100 + iforest_params: dict[str, Any] | None = None + scada_start: datetime | None = None + scada_end: datetime | None = None + sensor_nodes: list[str] | None = None + scheme_name: str | None = None + data_source: str = "monitoring" + simulation_scheme_name: str | None = None + simulation_scheme_type: str | None = None + + +@router.post("/detect/") +async def detect_burst( + data: BurstDetectionRequest, + username: str = Depends(get_current_keycloak_username), +) -> dict[str, Any]: + try: + return run_burst_detection(**data.model_dump(), username=username) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) + + +@router.get("/schemes/") +async def query_burst_detection_schemes( + network: str, + query_date: datetime | None = None, +) -> list[dict[str, Any]]: + try: + return list_burst_detection_schemes(network=network, query_date=query_date) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) + + +@router.get("/schemes/{scheme_name}") +async def query_burst_detection_scheme_detail( + network: str, + scheme_name: str, +) -> dict[str, Any]: + try: + return get_burst_detection_scheme_detail(network=network, scheme_name=scheme_name) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) diff --git a/app/api/v1/endpoints/burst_location.py b/app/api/v1/endpoints/burst_location.py new file mode 100644 index 0000000..e9ec3e4 --- /dev/null +++ b/app/api/v1/endpoints/burst_location.py @@ -0,0 +1,65 @@ +from typing import Any +from datetime import datetime + +from typing import Literal + +from fastapi import APIRouter, Depends, HTTPException +from pydantic import BaseModel + +from app.auth.keycloak_dependencies import get_current_keycloak_username +from app.services.burst_location import ( + get_burst_location_scheme_detail, + list_burst_location_schemes, + run_burst_location_by_network, +) + +router = APIRouter() + + +class BurstLocationRequest(BaseModel): + network: str + data_source: Literal["monitoring", "simulation"] = "monitoring" + pressure_scada_ids: list[str] | None = None + burst_pressure: dict[str, float] | list[dict[str, Any]] | None = None + normal_pressure: dict[str, float] | list[dict[str, Any]] | None = None + burst_leakage: float + flow_scada_ids: list[str] | None = None + burst_flow: dict[str, float] | list[dict[str, Any]] | None = None + normal_flow: dict[str, float] | list[dict[str, Any]] | None = None + min_dpressure: float = 2.0 + basic_pressure: float = 10.0 + scada_burst_start: datetime | None = None + scada_burst_end: datetime | None = None + use_scada_flow: bool = False + scheme_name: str | None = None + simulation_scheme_name: str | None = None + simulation_scheme_type: str | None = None + + +@router.post("/locate/") +async def locate_burst( + data: BurstLocationRequest, + username: str = Depends(get_current_keycloak_username), +) -> dict[str, Any]: + try: + return run_burst_location_by_network(**data.model_dump(), username=username) + except (TypeError, ValueError) as exc: + raise HTTPException(status_code=400, detail=str(exc)) + + +@router.get("/schemes/") +async def query_burst_schemes( + network: str, query_date: datetime | None = None +) -> list[dict[str, Any]]: + try: + return list_burst_location_schemes(network=network, query_date=query_date) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) + + +@router.get("/schemes/{scheme_name}") +async def query_burst_scheme_detail(network: str, scheme_name: str) -> dict[str, Any]: + try: + return get_burst_location_scheme_detail(network=network, scheme_name=scheme_name) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) diff --git a/app/api/v1/endpoints/cache.py b/app/api/v1/endpoints/cache.py new file mode 100644 index 0000000..06d6bb1 --- /dev/null +++ b/app/api/v1/endpoints/cache.py @@ -0,0 +1,37 @@ +from fastapi import APIRouter +from app.infra.cache.redis_client import redis_client + +router = APIRouter() + +@router.post("/clearrediskey/") +async def fastapi_clear_redis_key(key: str): + redis_client.delete(key) + return True + + +@router.post("/clearrediskeys/") +async def fastapi_clear_redis_keys(keys: str): + # delete keys contains the key + matched_keys = redis_client.keys(f"*{keys}*") + if matched_keys: + redis_client.delete(*matched_keys) + + return True + + +@router.post("/clearallredis/") +async def fastapi_clear_all_redis(): + redis_client.flushdb() + return True + + +@router.get("/queryredis/") +async def fastapi_query_redis(): + # Helper to decode bytes to str for JSON response if needed, + # but original just returned keys (which might be bytes in redis-py unless decode_responses=True) + # create_redis_client usually sets decode_responses=False by default. + # We will assume user handles bytes or we should decode. + # Original just returned redis_client.keys("*") + keys = redis_client.keys("*") + # Clean output for API + return [k.decode('utf-8') if isinstance(k, bytes) else k for k in keys] diff --git a/app/api/v1/endpoints/components/controls.py b/app/api/v1/endpoints/components/controls.py new file mode 100644 index 0000000..3f89510 --- /dev/null +++ b/app/api/v1/endpoints/components/controls.py @@ -0,0 +1,40 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + get_control, + get_control_schema, + get_rule, + get_rule_schema, + set_control, + set_rule, +) + +router = APIRouter() + +@router.get("/getcontrolschema/") +async def fastapi_get_control_schema(network: str) -> dict[str, dict[str, Any]]: + return get_control_schema(network) + +@router.get("/getcontrolproperties/") +async def fastapi_get_control_properties(network: str) -> dict[str, Any]: + return get_control(network) + +@router.post("/setcontrolproperties/", response_model=None) +async def fastapi_set_control_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_control(network, ChangeSet(props)) + +@router.get("/getruleschema/") +async def fastapi_get_rule_schema(network: str) -> dict[str, dict[str, Any]]: + return get_rule_schema(network) + +@router.get("/getruleproperties/") +async def fastapi_get_rule_properties(network: str) -> dict[str, Any]: + return get_rule(network) + +@router.post("/setruleproperties/", response_model=None) +async def fastapi_set_rule_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_rule(network, ChangeSet(props)) diff --git a/app/api/v1/endpoints/components/curves.py b/app/api/v1/endpoints/components/curves.py new file mode 100644 index 0000000..33aabe0 --- /dev/null +++ b/app/api/v1/endpoints/components/curves.py @@ -0,0 +1,52 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_curve, + delete_curve, + get_curve, + get_curve_schema, + get_curves, + is_curve, + set_curve, +) + +router = APIRouter() + +@router.get("/getcurveschema") +async def fastapi_get_curve_schema(network: str) -> dict[str, dict[str, Any]]: + return get_curve_schema(network) + +@router.post("/addcurve/", response_model=None) +async def fastapi_add_curve(network: str, curve: str, req: Request) -> ChangeSet: + props = await req.json() + ps = { + "id": curve, + } | props + return add_curve(network, ChangeSet(ps)) + +@router.post("/deletecurve/", response_model=None) +async def fastapi_delete_curve(network: str, curve: str) -> ChangeSet: + ps = {"id": curve} + return delete_curve(network, ChangeSet(ps)) + +@router.get("/getcurveproperties/") +async def fastapi_get_curve_properties(network: str, curve: str) -> dict[str, Any]: + return get_curve(network, curve) + +@router.post("/setcurveproperties/", response_model=None) +async def fastapi_set_curve_properties( + network: str, curve: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": curve} | props + return set_curve(network, ChangeSet(ps)) + +@router.get("/getcurves/") +async def fastapi_get_curves(network: str) -> list[str]: + return get_curves(network) + +@router.get("/iscurve/") +async def fastapi_is_curve(network: str, curve: str) -> bool: + return is_curve(network, curve) diff --git a/app/api/v1/endpoints/components/options.py b/app/api/v1/endpoints/components/options.py new file mode 100644 index 0000000..c05db24 --- /dev/null +++ b/app/api/v1/endpoints/components/options.py @@ -0,0 +1,75 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + get_energy, + get_energy_schema, + get_option_v3, + get_option_v3_schema, + get_pump_energy, + get_pump_energy_schema, + get_time, + get_time_schema, + set_energy, + set_option_v3, + set_pump_energy, + set_time, +) + +router = APIRouter() + +@router.get("/gettimeschema") +async def fastapi_get_time_schema(network: str) -> dict[str, dict[str, Any]]: + return get_time_schema(network) + +@router.get("/gettimeproperties/") +async def fastapi_get_time_properties(network: str) -> dict[str, Any]: + return get_time(network) + +@router.post("/settimeproperties/", response_model=None) +async def fastapi_set_time_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_time(network, ChangeSet(props)) + +@router.get("/getenergyschema/") +async def fastapi_get_energy_schema(network: str) -> dict[str, dict[str, Any]]: + return get_energy_schema(network) + +@router.get("/getenergyproperties/") +async def fastapi_get_energy_properties(network: str) -> dict[str, Any]: + return get_energy(network) + +@router.post("/setenergyproperties/", response_model=None) +async def fastapi_set_energy_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_energy(network, ChangeSet(props)) + +@router.get("/getpumpenergyschema/") +async def fastapi_get_pump_energy_schema(network: str) -> dict[str, dict[str, Any]]: + return get_pump_energy_schema(network) + +@router.get("/getpumpenergyproperties//") +async def fastapi_get_pump_energy_proeprties(network: str, pump: str) -> dict[str, Any]: + return get_pump_energy(network, pump) + +@router.get("/setpumpenergyproperties//", response_model=None) +async def fastapi_set_pump_energy_properties( + network: str, pump: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": pump} | props + return set_pump_energy(network, ChangeSet(ps)) + +@router.get("/getoptionschema/") +async def fastapi_get_option_schema(network: str) -> dict[str, dict[str, Any]]: + return get_option_v3_schema(network) + +@router.get("/getoptionproperties/") +async def fastapi_get_option_properties(network: str) -> dict[str, Any]: + return get_option_v3(network) + +@router.post("/setoptionproperties/", response_model=None) +async def fastapi_set_option_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_option_v3(network, ChangeSet(props)) diff --git a/app/api/v1/endpoints/components/patterns.py b/app/api/v1/endpoints/components/patterns.py new file mode 100644 index 0000000..b42e14a --- /dev/null +++ b/app/api/v1/endpoints/components/patterns.py @@ -0,0 +1,52 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_pattern, + delete_pattern, + get_pattern, + get_pattern_schema, + get_patterns, + is_pattern, + set_pattern, +) + +router = APIRouter() + +@router.get("/getpatternschema") +async def fastapi_get_pattern_schema(network: str) -> dict[str, dict[str, Any]]: + return get_pattern_schema(network) + +@router.post("/addpattern/", response_model=None) +async def fastapi_add_pattern(network: str, pattern: str, req: Request) -> ChangeSet: + props = await req.json() + ps = { + "id": pattern, + } | props + return add_pattern(network, ChangeSet(ps)) + +@router.post("/deletepattern/", response_model=None) +async def fastapi_delete_pattern(network: str, pattern: str) -> ChangeSet: + ps = {"id": pattern} + return delete_pattern(network, ChangeSet(ps)) + +@router.get("/getpatternproperties/") +async def fastapi_get_pattern_properties(network: str, pattern: str) -> dict[str, Any]: + return get_pattern(network, pattern) + +@router.post("/setpatternproperties/", response_model=None) +async def fastapi_set_pattern_properties( + network: str, pattern: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": pattern} | props + return set_pattern(network, ChangeSet(ps)) + +@router.get("/ispattern/") +async def fastapi_is_pattern(network: str, pattern: str) -> bool: + return is_pattern(network, pattern) + +@router.get("/getpatterns/") +async def fastapi_get_patterns(network: str) -> list[str]: + return get_patterns(network) diff --git a/app/api/v1/endpoints/components/quality.py b/app/api/v1/endpoints/components/quality.py new file mode 100644 index 0000000..01fc1d1 --- /dev/null +++ b/app/api/v1/endpoints/components/quality.py @@ -0,0 +1,147 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_mixing, + add_source, + api, + delete_mixing, + delete_source, + get_emitter, + get_emitter_schema, + get_mixing, + get_mixing_schema, + get_pipe_reaction, + get_pipe_reaction_schema, + get_quality, + get_quality_schema, + get_reaction, + get_reaction_schema, + get_source, + get_source_schema, + get_tank_reaction, + get_tank_reaction_schema, + set_emitter, + set_pipe_reaction, + set_quality, + set_reaction, + set_source, + set_tank_reaction, +) + +router = APIRouter() + +@router.get("/getqualityschema/") +async def fastapi_get_quality_schema(network: str) -> dict[str, dict[str, Any]]: + return get_quality_schema(network) + +@router.get("/getqualityproperties/") +async def fastapi_get_quality_properties(network: str, node: str) -> dict[str, Any]: + return get_quality(network, node) + +@router.post("/setqualityproperties/", response_model=None) +async def fastapi_set_quality_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_quality(network, ChangeSet(props)) + +@router.get("/getemitterschema") +async def fastapi_get_emitter_schema(network: str) -> dict[str, dict[str, Any]]: + return get_emitter_schema(network) + +@router.get("/getemitterproperties/") +async def fastapi_get_emitter_properties(network: str, junction: str) -> dict[str, Any]: + return get_emitter(network, junction) + +@router.post("/setemitterproperties/", response_model=None) +async def fastapi_set_emitter_properties( + network: str, junction: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"junction": junction} | props + return set_emitter(network, ChangeSet(ps)) + +@router.get("/getsourcechema/") +async def fastapi_get_source_schema(network: str) -> dict[str, dict[str, Any]]: + return get_source_schema(network) + +@router.get("/getsource/") +async def fastapi_get_source(network: str, node: str) -> dict[str, Any]: + return get_source(network, node) + +@router.post("/setsource/", response_model=None) +async def fastapi_set_source(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_source(network, ChangeSet(props)) + +@router.post("/addsource/", response_model=None) +async def fastapi_add_source(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_source(network, ChangeSet(props)) + +@router.post("/deletesource/", response_model=None) +async def fastapi_delete_source(network: str, node: str) -> ChangeSet: + props = {"node": node} + return delete_source(network, ChangeSet(props)) + +@router.get("/getreactionschema/") +async def fastapi_get_reaction_schema(network: str) -> dict[str, dict[str, Any]]: + return get_reaction_schema(network) + +@router.get("/getreaction/") +async def fastapi_get_reaction(network: str) -> dict[str, Any]: + return get_reaction(network) + +@router.post("/setreaction/", response_model=None) +async def fastapi_set_reaction(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_reaction(network, ChangeSet(props)) + +@router.get("/getpipereactionschema/") +async def fastapi_get_pipe_reaction_schema(network: str) -> dict[str, dict[str, Any]]: + return get_pipe_reaction_schema(network) + +@router.get("/getpipereaction/") +async def fastapi_get_pipe_reaction(network: str, pipe: str) -> dict[str, Any]: + return get_pipe_reaction(network, pipe) + +@router.post("/setpipereaction/", response_model=None) +async def fastapi_set_pipe_reaction(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_pipe_reaction(network, ChangeSet(props)) + +@router.get("/gettankreactionschema/") +async def fastapi_get_tank_reaction_schema(network: str) -> dict[str, dict[str, Any]]: + return get_tank_reaction_schema(network) + +@router.get("/gettankreaction/") +async def fastapi_get_tank_reaction(network: str, tank: str) -> dict[str, Any]: + return get_tank_reaction(network, tank) + +@router.post("/settankreaction/", response_model=None) +async def fastapi_set_tank_reaction(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_tank_reaction(network, ChangeSet(props)) + +@router.get("/getmixingschema/") +async def fastapi_get_mixing_schema(network: str) -> dict[str, dict[str, Any]]: + return get_mixing_schema(network) + +@router.get("/getmixing/") +async def fastapi_get_mixing(network: str, tank: str) -> dict[str, Any]: + return get_mixing(network, tank) + +@router.post("/setmixing/", response_model=None) +async def fastapi_set_mixing(network: str, req: Request) -> ChangeSet: + props = await req.json() + return api.set_mixing(network, ChangeSet(props)) + +@router.post("/addmixing/", response_model=None) +async def fastapi_add_mixing(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_mixing(network, ChangeSet(props)) + +@router.post("/deletemixing/", response_model=None) +async def fastapi_delete_mixing(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_mixing(network, ChangeSet(props)) diff --git a/app/api/v1/endpoints/components/visuals.py b/app/api/v1/endpoints/components/visuals.py new file mode 100644 index 0000000..65f1cad --- /dev/null +++ b/app/api/v1/endpoints/components/visuals.py @@ -0,0 +1,94 @@ +from fastapi import APIRouter, Request, Response +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_label, + add_vertex, + delete_label, + delete_vertex, + get_all_vertex_links, + get_all_vertices, + get_backdrop, + get_backdrop_schema, + get_label, + get_label_schema, + get_vertex, + get_vertex_schema, + set_backdrop, + set_label, + set_vertex, +) +from fastapi.responses import PlainTextResponse +import json + +router = APIRouter() + +@router.get("/getvertexschema/") +async def fastapi_get_vertex_schema(network: str) -> dict[str, dict[str, Any]]: + return get_vertex_schema(network) + +@router.get("/getvertexproperties/") +async def fastapi_get_vertex_properties(network: str, link: str) -> dict[str, Any]: + return get_vertex(network, link) + +@router.post("/setvertexproperties/", response_model=None) +async def fastapi_set_vertex_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_vertex(network, ChangeSet(props)) + +@router.post("/addvertex/", response_model=None) +async def fastapi_add_vertex(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_vertex(network, ChangeSet(props)) + +@router.post("/deletevertex/", response_model=None) +async def fastapi_delete_vertex(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_vertex(network, ChangeSet(props)) + +@router.get("/getallvertexlinks/", response_class=PlainTextResponse) +async def fastapi_get_all_vertex_links(network: str) -> list[str]: + return json.dumps(get_all_vertex_links(network)) + +@router.get("/getallvertices/", response_class=PlainTextResponse) +async def fastapi_get_all_vertices(network: str) -> list[dict[str, Any]]: + return json.dumps(get_all_vertices(network)) + +@router.get("/getlabelschema/") +async def fastapi_get_label_schema(network: str) -> dict[str, dict[str, Any]]: + return get_label_schema(network) + +@router.get("/getlabelproperties/") +async def fastapi_get_label_properties( + network: str, x: float, y: float +) -> dict[str, Any]: + return get_label(network, x, y) + +@router.post("/setlabelproperties/", response_model=None) +async def fastapi_set_label_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_label(network, ChangeSet(props)) + +@router.post("/addlabel/", response_model=None) +async def fastapi_add_label(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_label(network, ChangeSet(props)) + +@router.post("/deletelabel/", response_model=None) +async def fastapi_delete_label(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_label(network, ChangeSet(props)) + +@router.get("/getbackdropschema/") +async def fastapi_get_backdrop_schema(network: str) -> dict[str, dict[str, Any]]: + return get_backdrop_schema(network) + +@router.get("/getbackdropproperties/") +async def fastapi_get_backdrop_properties(network: str) -> dict[str, Any]: + return get_backdrop(network) + +@router.post("/setbackdropproperties/", response_model=None) +async def fastapi_set_backdrop_properties(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_backdrop(network, ChangeSet(props)) diff --git a/app/api/v1/endpoints/data_query.py b/app/api/v1/endpoints/data_query.py new file mode 100644 index 0000000..2413ca3 --- /dev/null +++ b/app/api/v1/endpoints/data_query.py @@ -0,0 +1,388 @@ +from typing import Any, List, Dict, Optional +import logging +from datetime import datetime, timedelta, timezone, time as dt_time +import msgpack +from fastapi import APIRouter +from pydantic import BaseModel +from py_linq import Enumerable + +import app.infra.db.influxdb.api as influxdb_api +import app.services.time_api as time_api +from app.infra.cache.redis_client import redis_client, encode_datetime, decode_datetime + +router = APIRouter() +logger = logging.getLogger(__name__) + +# Basic Node/Link Latest Record Queries + +@router.get("/querynodelatestrecordbyid/") +async def fastapi_query_node_latest_record_by_id(id: str) -> Any: + return influxdb_api.query_latest_record_by_ID(id, type="node") + +@router.get("/querylinklatestrecordbyid/") +async def fastapi_query_link_latest_record_by_id(id: str) -> Any: + return influxdb_api.query_latest_record_by_ID(id, type="link") + +@router.get("/queryscadalatestrecordbyid/") +async def fastapi_query_scada_latest_record_by_id(id: str) -> Any: + return influxdb_api.query_latest_record_by_ID(id, type="scada") + +# Time-based Queries + +@router.get("/queryallrecordsbytime/") +async def fastapi_query_all_records_by_time(querytime: str) -> dict[str, list]: + results: tuple = influxdb_api.query_all_records_by_time(query_time=querytime) + return {"nodes": results[0], "links": results[1]} + +@router.get("/queryallrecordsbytimeproperty/") +async def fastapi_query_all_record_by_time_property( + querytime: str, type: str, property: str, bucket: str = "realtime_simulation_result" +) -> dict[str, list]: + results: tuple = influxdb_api.query_all_record_by_time_property( + query_time=querytime, type=type, property=property, bucket=bucket + ) + return {"results": results} + +@router.get("/queryallschemerecordsbytimeproperty/") +async def fastapi_query_all_scheme_record_by_time_property( + querytime: str, + type: str, + property: str, + schemename: str, + bucket: str = "scheme_simulation_result", +) -> dict[str, list]: + """ + 查询指定方案某一时刻的所有记录,查询 'node' 或 'link' 的某一属性值 + """ + results: list = influxdb_api.query_all_scheme_record_by_time_property( + query_time=querytime, + type=type, + property=property, + scheme_name=schemename, + bucket=bucket, + ) + return {"results": results} + +@router.get("/querysimulationrecordsbyidtime/") +async def fastapi_query_simulation_record_by_ids_time( + id: str, querytime: str, type: str, bucket: str = "realtime_simulation_result" +) -> dict[str, list]: + results: tuple = influxdb_api.query_simulation_result_by_ID_time( + ID=id, type=type, query_time=querytime, bucket=bucket + ) + return {"results": results} + +@router.get("/queryschemesimulationrecordsbyidtime/") +async def fastapi_query_scheme_simulation_record_by_ids_time( + scheme_name: str, + id: str, + querytime: str, + type: str, + bucket: str = "scheme_simulation_result", +) -> dict[str, list]: + results: tuple = influxdb_api.query_scheme_simulation_result_by_ID_time( + scheme_name=scheme_name, ID=id, type=type, query_time=querytime, bucket=bucket + ) + return {"results": results} + +# Date-based Queries with Caching + +@router.get("/queryallrecordsbydate/") +async def fastapi_query_all_records_by_date(querydate: str) -> dict: + is_today_or_future = time_api.is_today_or_future(querydate) + logger.info(f"isToday or future: {is_today_or_future}") + + cache_key = f"queryallrecordsbydate_{querydate}" + + if not is_today_or_future: + data = redis_client.get(cache_key) + if data: + results = msgpack.unpackb(data, object_hook=decode_datetime) + logger.info("return from cache redis") + return results + + logger.info("query from influxdb") + nodes_links: tuple = influxdb_api.query_all_records_by_date(query_date=querydate) + results = {"nodes": nodes_links[0], "links": nodes_links[1]} + + if not is_today_or_future: + logger.info("save to cache redis") + redis_client.set(cache_key, msgpack.packb(results, default=encode_datetime)) + + logger.info("return results") + return results + +@router.get("/queryallrecordsbytimerange/") +async def fastapi_query_all_records_by_time_range( + starttime: str, endtime: str +) -> dict[str, list]: + cache_key = f"queryallrecordsbytimerange_{starttime}_{endtime}" + + if not time_api.is_today_or_future(starttime): + data = redis_client.get(cache_key) + if data: + loaded_dict = msgpack.unpackb(data, object_hook=decode_datetime) + return loaded_dict + + nodes_links: tuple = influxdb_api.query_all_records_by_time_range( + starttime=starttime, endtime=endtime + ) + results = {"nodes": nodes_links[0], "links": nodes_links[1]} + + if not time_api.is_today_or_future(starttime): + redis_client.set(cache_key, msgpack.packb(results, default=encode_datetime)) + + return results + +@router.get("/queryallrecordsbydatewithtype/") +async def fastapi_query_all_records_by_date_with_type( + querydate: str, querytype: str +) -> list: + cache_key = f"queryallrecordsbydatewithtype_{querydate}_{querytype}" + data = redis_client.get(cache_key) + if data: + loaded_dict = msgpack.unpackb(data, object_hook=decode_datetime) + return loaded_dict + + results = influxdb_api.query_all_records_by_date_with_type( + query_date=querydate, query_type=querytype + ) + + packed = msgpack.packb(results, default=encode_datetime) + redis_client.set(cache_key, packed) + + return results + +@router.get("/queryallrecordsbyidsdatetype/") +async def fastapi_query_all_records_by_ids_date_type( + ids: str, querydate: str, querytype: str +) -> list: + cache_key = f"queryallrecordsbydatewithtype_{querydate}_{querytype}" + data = redis_client.get(cache_key) + + results = [] + if data: + results = msgpack.unpackb(data, object_hook=decode_datetime) + else: + results = influxdb_api.query_all_records_by_date_with_type( + query_date=querydate, query_type=querytype + ) + packed = msgpack.packb(results, default=encode_datetime) + redis_client.set(cache_key, packed) + + query_ids = ids.split(",") + # Using Enumerable from py_linq as in original code + e_results = Enumerable(results) + lst_results = e_results.where(lambda x: x["ID"] in query_ids).to_list() + + return lst_results + +@router.get("/queryallrecordsbydateproperty/") +async def fastapi_query_all_records_by_date_property( + querydate: str, querytype: str, property: str +) -> list[dict]: + cache_key = f"queryallrecordsbydateproperty_{querydate}_{querytype}_{property}" + data = redis_client.get(cache_key) + if data: + loaded_dict = msgpack.unpackb(data, object_hook=decode_datetime) + return loaded_dict + + result_dict = influxdb_api.query_all_record_by_date_property( + query_date=querydate, type=querytype, property=property + ) + packed = msgpack.packb(result_dict, default=encode_datetime) + redis_client.set(cache_key, packed) + + return result_dict + +# Curve Queries + +@router.get("/querynodecurvebyidpropertydaterange/") +async def fastapi_query_node_curve_by_id_property_daterange( + id: str, prop: str, startdate: str, enddate: str +): + return influxdb_api.query_curve_by_ID_property_daterange( + id, type="node", property=prop, start_date=startdate, end_date=enddate + ) + +@router.get("/querylinkcurvebyidpropertydaterange/") +async def fastapi_query_link_curve_by_id_property_daterange( + id: str, prop: str, startdate: str, enddate: str +): + return influxdb_api.query_curve_by_ID_property_daterange( + id, type="link", property=prop, start_date=startdate, end_date=enddate + ) + +# SCADA Data Queries + +@router.get("/queryscadadatabydeviceidandtime/") +async def fastapi_query_scada_data_by_device_id_and_time(ids: str, querytime: str): + query_ids = ids.split(",") + logger.info(querytime) + return influxdb_api.query_SCADA_data_by_device_ID_and_time( + query_ids_list=query_ids, query_time=querytime + ) + +@router.get("/queryscadadatabydeviceidandtimerange/") +async def fastapi_query_scada_data_by_device_id_and_time_range( + ids: str, starttime: str, endtime: str +): + print(f"query_ids: {ids}, starttime: {starttime}, endtime: {endtime}") + query_ids = ids.split(",") + return influxdb_api.query_SCADA_data_by_device_ID_and_timerange( + query_ids_list=query_ids, start_time=starttime, end_time=endtime + ) + +@router.get("/queryfillingscadadatabydeviceidandtimerange/") +async def fastapi_query_filling_scada_data_by_device_id_and_time_range( + ids: str, starttime: str, endtime: str +): + print(f"query_ids: {ids}, starttime: {starttime}, endtime: {endtime}") + query_ids = ids.split(",") + return influxdb_api.query_filling_SCADA_data_by_device_ID_and_timerange( + query_ids_list=query_ids, start_time=starttime, end_time=endtime + ) + +@router.get("/querycleaningscadadatabydeviceidandtimerange/") +async def fastapi_query_cleaning_scada_data_by_device_id_and_time_range( + ids: str, starttime: str, endtime: str +): + print(f"query_ids: {ids}, starttime: {starttime}, endtime: {endtime}") + query_ids = ids.split(",") + return influxdb_api.query_cleaning_SCADA_data_by_device_ID_and_timerange( + query_ids_list=query_ids, start_time=starttime, end_time=endtime + ) + +@router.get("/querysimulationscadadatabydeviceidandtimerange/") +async def fastapi_query_simulation_scada_data_by_device_id_and_time_range( + ids: str, starttime: str, endtime: str +): + print(f"query_ids: {ids}, starttime: {starttime}, endtime: {endtime}") + query_ids = ids.split(",") + return influxdb_api.query_simulation_SCADA_data_by_device_ID_and_timerange( + query_ids_list=query_ids, start_time=starttime, end_time=endtime + ) + +@router.get("/querycleanedscadadatabydeviceidandtimerange/") +async def fastapi_query_cleaned_scada_data_by_device_id_and_time_range( + ids: str, starttime: str, endtime: str +): + print(f"query_ids: {ids}, starttime: {starttime}, endtime: {endtime}") + query_ids = ids.split(",") + return influxdb_api.query_cleaned_SCADA_data_by_device_ID_and_timerange( + query_ids_list=query_ids, start_time=starttime, end_time=endtime + ) + +@router.get("/queryscadadatabydeviceidanddate/") +async def fastapi_query_scada_data_by_device_id_and_date(ids: str, querydate: str): + query_ids = ids.split(",") + return influxdb_api.query_SCADA_data_by_device_ID_and_date( + query_ids_list=query_ids, query_date=querydate + ) + +@router.get("/queryallscadarecordsbydate/") +async def fastapi_query_all_scada_records_by_date(querydate: str): + is_today_or_future = time_api.is_today_or_future(querydate) + logger.info(f"isToday or future: {is_today_or_future}") + + cache_key = f"queryallscadarecordsbydate_{querydate}" + + if not is_today_or_future: + data = redis_client.get(cache_key) + if data: + loaded_dict = msgpack.unpackb(data, object_hook=decode_datetime) + logger.info("return from cache redis") + return loaded_dict + + logger.info("query from influxdb") + result_dict = influxdb_api.query_all_SCADA_records_by_date(query_date=querydate) + + if not is_today_or_future: + logger.info("save to cache redis") + packed = msgpack.packb(result_dict, default=encode_datetime) + redis_client.set(cache_key, packed) + + logger.info("return results") + return result_dict + +@router.get("/queryallschemeallrecords/") +async def fastapi_query_all_scheme_all_records( + schemetype: str, schemename: str, querydate: str +) -> tuple: + cache_key = f"queryallschemeallrecords_{schemetype}_{schemename}_{querydate}" + data = redis_client.get(cache_key) + if data: + loaded_dict = msgpack.unpackb(data, object_hook=decode_datetime) + return loaded_dict + + results = influxdb_api.query_scheme_all_record( + scheme_type=schemetype, scheme_name=schemename, query_date=querydate + ) + packed = msgpack.packb(results, default=encode_datetime) + redis_client.set(cache_key, packed) + + return results + +@router.get("/queryschemeallrecordsproperty/") +async def fastapi_query_all_scheme_all_records_property( + schemetype: str, schemename: str, querydate: str, querytype: str, queryproperty: str +) -> Optional[List]: + cache_key = f"queryallschemeallrecords_{schemetype}_{schemename}_{querydate}" + data = redis_client.get(cache_key) + all_results = None + if data: + all_results = msgpack.unpackb(data, object_hook=decode_datetime) + else: + all_results = influxdb_api.query_scheme_all_record( + scheme_type=schemetype, scheme_name=schemename, query_date=querydate + ) + packed = msgpack.packb(all_results, default=encode_datetime) + redis_client.set(cache_key, packed) + + results = None + if querytype == "node": + results = all_results[0] + elif querytype == "link": + results = all_results[1] + + return results + +@router.get("/queryinfluxdbbuckets/") +async def fastapi_query_influxdb_buckets(): + return influxdb_api.query_buckets() + +@router.get("/queryinfluxdbbucketmeasurements/") +async def fastapi_query_influxdb_bucket_measurements(bucket: str): + return influxdb_api.query_measurements(bucket=bucket) + +############################################################ +# download history data +############################################################ + +class Download_History_Data_Manually(BaseModel): + """ + download_date:样式如 datetime(2025, 5, 4) + """ + + download_date: datetime + + +@router.post("/download_history_data_manually/") +async def fastapi_download_history_data_manually( + data: Download_History_Data_Manually, +) -> None: + item = data.dict() + tz = timezone(timedelta(hours=8)) + begin_dt = datetime.combine(item.get("download_date").date(), dt_time.min).replace( + tzinfo=tz + ) + end_dt = datetime.combine(item.get("download_date").date(), dt_time(23, 59, 59)).replace( + tzinfo=tz + ) + + begin_time = begin_dt.isoformat() + end_time = end_dt.isoformat() + + influxdb_api.download_history_data_manually( + begin_time=begin_time, end_time=end_time + ) diff --git a/app/api/v1/endpoints/extension.py b/app/api/v1/endpoints/extension.py new file mode 100644 index 0000000..5939f61 --- /dev/null +++ b/app/api/v1/endpoints/extension.py @@ -0,0 +1,31 @@ +from typing import List, Any +from fastapi import APIRouter, Request, HTTPException +from app.services.tjnetwork import ( + ChangeSet, + get_all_extension_data_keys, + get_all_extension_data, + get_extension_data, + set_extension_data +) + +router = APIRouter() + +@router.get("/getallextensiondatakeys/") +async def get_all_extension_data_keys_endpoint(network: str) -> list[str]: + return get_all_extension_data_keys(network) + +@router.get("/getallextensiondata/") +async def get_all_extension_data_endpoint(network: str) -> dict[str, Any]: + return get_all_extension_data(network) + +@router.get("/getextensiondata/") +async def get_extension_data_endpoint(network: str, key: str) -> str | None: + return get_extension_data(network, key) + +@router.post("/setextensiondata/", response_model=None) +async def set_extension_data_endpoint(network: str, req: Request) -> ChangeSet: + props = await req.json() + print(props) + cs = set_extension_data(network, ChangeSet(props)) + print(cs.operations[0]) + return cs diff --git a/app/api/v1/endpoints/leakage.py b/app/api/v1/endpoints/leakage.py new file mode 100644 index 0000000..8277745 --- /dev/null +++ b/app/api/v1/endpoints/leakage.py @@ -0,0 +1,69 @@ +import os +from typing import Any +from datetime import datetime + +from fastapi import APIRouter, Depends, HTTPException +from pydantic import BaseModel + +from app.auth.keycloak_dependencies import get_current_keycloak_username +from app.services.leakage_identifier import ( + get_leakage_identify_scheme_detail, + list_leakage_identify_schemes, + run_leakage_identification, +) + +router = APIRouter() +DEFAULT_N_WORKERS = max(1, min((os.cpu_count() or 1) - 1, 4)) + + +class LeakageIdentifyRequest(BaseModel): + network: str + observed_pressure_data: str | dict[str, list[Any]] | list[dict[str, Any]] | None = ( + None + ) + start_time: float = 0 + duration: float = 24 + timestep: float = 5 + q_sum: float = 0.2 + q_sum_unit: str = "m3/s" + output_dir: str = "db_inp" + pop_size: int = 50 + max_gen: int = 100 + n_workers: int = DEFAULT_N_WORKERS + output_flow_unit: str = "m3/s" + dma_count: int | None = None + scada_start: datetime | None = None + scada_end: datetime | None = None + sensor_nodes: list[str] | None = None + scheme_name: str | None = None + + +@router.post("/identify/") +async def identify_leakage( + data: LeakageIdentifyRequest, + username: str = Depends(get_current_keycloak_username), +) -> dict[str, Any]: + try: + return run_leakage_identification(**data.model_dump(), username=username) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) + + +@router.get("/schemes/") +async def query_leakage_schemes( + network: str, query_date: datetime | None = None +) -> list[dict[str, Any]]: + try: + return list_leakage_identify_schemes(network=network, query_date=query_date) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) + + +@router.get("/schemes/{scheme_name}") +async def query_leakage_scheme_detail(network: str, scheme_name: str) -> dict[str, Any]: + try: + return get_leakage_identify_scheme_detail( + network=network, scheme_name=scheme_name + ) + except Exception as exc: + raise HTTPException(status_code=400, detail=str(exc)) diff --git a/app/api/v1/endpoints/meta.py b/app/api/v1/endpoints/meta.py new file mode 100644 index 0000000..1e86a44 --- /dev/null +++ b/app/api/v1/endpoints/meta.py @@ -0,0 +1,101 @@ +import logging +from fastapi import APIRouter, Depends, HTTPException, status +from psycopg import AsyncConnection +from sqlalchemy import text +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.ext.asyncio import AsyncSession + +from app.auth.project_dependencies import ( + ProjectContext, + get_project_context, + get_project_pg_session, + get_project_timescale_connection, + get_metadata_repository, +) +from app.auth.metadata_dependencies import get_current_metadata_user +from app.core.config import settings +from app.domain.schemas.metadata import ( + GeoServerConfigResponse, + ProjectMetaResponse, + ProjectSummaryResponse, +) +from app.infra.repositories.metadata_repository import MetadataRepository + +router = APIRouter() +logger = logging.getLogger(__name__) + + +@router.get("/meta/project", response_model=ProjectMetaResponse) +async def get_project_metadata( + ctx: ProjectContext = Depends(get_project_context), + metadata_repo: MetadataRepository = Depends(get_metadata_repository), +): + project = await metadata_repo.get_project_by_id(ctx.project_id) + if not project: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Project not found" + ) + geoserver = await metadata_repo.get_geoserver_config(ctx.project_id) + geoserver_payload = ( + GeoServerConfigResponse( + gs_base_url=geoserver.gs_base_url, + gs_admin_user=geoserver.gs_admin_user, + gs_datastore_name=geoserver.gs_datastore_name, + default_extent=geoserver.default_extent, + srid=geoserver.srid, + ) + if geoserver + else None + ) + return ProjectMetaResponse( + project_id=project.id, + name=project.name, + code=project.code, + description=project.description, + gs_workspace=project.gs_workspace, + status=project.status, + project_role=ctx.project_role, + geoserver=geoserver_payload, + ) + + +@router.get("/meta/projects", response_model=list[ProjectSummaryResponse]) +async def list_user_projects( + current_user=Depends(get_current_metadata_user), + metadata_repo: MetadataRepository = Depends(get_metadata_repository), +): + try: + projects = await metadata_repo.list_projects_for_user(current_user.id) + except SQLAlchemyError as exc: + logger.error( + "Metadata DB error while listing projects for user %s", + current_user.id, + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Metadata database error: {exc}", + ) from exc + return [ + ProjectSummaryResponse( + project_id=project.project_id, + name=project.name, + code=project.code, + description=project.description, + gs_workspace=project.gs_workspace, + status=project.status, + project_role=project.project_role, + ) + for project in projects + ] + + +@router.get("/meta/db/health") +async def project_db_health( + pg_session: AsyncSession = Depends(get_project_pg_session), + ts_conn: AsyncConnection = Depends(get_project_timescale_connection), +): + await pg_session.execute(text("SELECT 1")) + async with ts_conn.cursor() as cur: + await cur.execute("SELECT 1") + return {"postgres": "ok", "timescale": "ok"} diff --git a/app/api/v1/endpoints/misc.py b/app/api/v1/endpoints/misc.py new file mode 100644 index 0000000..d040df9 --- /dev/null +++ b/app/api/v1/endpoints/misc.py @@ -0,0 +1,55 @@ +from typing import Any +import random +from fastapi import APIRouter +from fastapi.responses import JSONResponse +from fastapi import status +from pydantic import BaseModel +from app.services.tjnetwork import ( + get_all_sensor_placements, + get_all_burst_locate_results, +) + +router = APIRouter() + + +@router.get("/getjson/") +async def fastapi_get_json(): + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content={ + "code": 400, + "message": "this is message", + "data": 123, + }, + ) + + +@router.get("/getallsensorplacements/") +async def fastapi_get_all_sensor_placements(network: str) -> list[dict[Any, Any]]: + return get_all_sensor_placements(network) + + +@router.get("/getallburstlocateresults/") +async def fastapi_get_all_burst_locate_results(network: str) -> list[dict[Any, Any]]: + return get_all_burst_locate_results(network) + + +class Item(BaseModel): + str_info: str + + +@router.post("/test_dict/") +async def fastapi_test_dict(data: Item) -> dict[str, str]: + item = data.dict() + return item + +@router.get("/getrealtimedata/") +async def fastapi_get_realtimedata(): + data = [random.randint(0, 100) for _ in range(100)] + return data + + +@router.get("/getsimulationresult/") +async def fastapi_get_simulationresult(): + data = [random.randint(0, 100) for _ in range(100)] + return data diff --git a/app/api/v1/endpoints/network/demands.py b/app/api/v1/endpoints/network/demands.py new file mode 100644 index 0000000..747788f --- /dev/null +++ b/app/api/v1/endpoints/network/demands.py @@ -0,0 +1,64 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + calculate_demand_to_network, + calculate_demand_to_nodes, + calculate_demand_to_region, + get_demand, + get_demand_schema, + set_demand, +) + +router = APIRouter() + +############################################################ +# demand 9.[DEMANDS] +############################################################ + +@router.get("/getdemandschema") +async def fastapi_get_demand_schema(network: str) -> dict[str, dict[str, Any]]: + return get_demand_schema(network) + + +@router.get("/getdemandproperties/") +async def fastapi_get_demand_properties(network: str, junction: str) -> dict[str, Any]: + return get_demand(network, junction) + + +# example: set_demand(p, ChangeSet({'junction': 'j1', 'demands': [{'demand': 10.0, 'pattern': None, 'category': 'x'}, {'demand': 20.0, 'pattern': None, 'category': None}]})) +@router.post("/setdemandproperties/", response_model=None) +async def fastapi_set_demand_properties( + network: str, junction: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"junction": junction} | props + return set_demand(network, ChangeSet(ps)) + +############################################################ +# water distribution 36.[Water Distribution] +############################################################ +@router.get("/calculatedemandtonodes/") +async def fastapi_calculate_demand_to_nodes( + network: str, req: Request +) -> dict[str, float]: + props = await req.json() + demand = props["demand"] + nodes = props["nodes"] + return calculate_demand_to_nodes(network, demand, nodes) + +@router.get("/calculatedemandtoregion/") +async def fastapi_calculate_demand_to_region( + network: str, req: Request +) -> dict[str, float]: + props = await req.json() + demand = props["demand"] + region = props["region"] + return calculate_demand_to_region(network, demand, region) + +@router.get("/calculatedemandtonetwork/") +async def fastapi_calculate_demand_to_network( + network: str, demand: float +) -> dict[str, float]: + return calculate_demand_to_network(network, demand) diff --git a/app/api/v1/endpoints/network/general.py b/app/api/v1/endpoints/network/general.py new file mode 100644 index 0000000..bfa0bd2 --- /dev/null +++ b/app/api/v1/endpoints/network/general.py @@ -0,0 +1,198 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + delete_junction, + delete_pipe, + delete_pump, + delete_reservoir, + delete_tank, + delete_valve, + get_all_scada_info, + get_element_properties, + get_element_properties_with_type, + get_element_type, + get_element_type_value, + get_link_properties, + get_link_type, + get_links, + get_node_links, + get_node_properties, + get_node_type, + get_nodes, + get_scada_info, + get_status, + get_status_schema, + get_title, + get_title_schema, + is_junction, + is_link, + is_node, + is_pipe, + is_pump, + is_reservoir, + is_tank, + is_valve, + set_status, + set_title, +) + +router = APIRouter() + +############################################################ +# type +############################################################ + +@router.get("/isnode/") +async def fastapi_is_node(network: str, node: str) -> bool: + return is_node(network, node) + +@router.get("/isjunction/") +async def fastapi_is_junction(network: str, node: str) -> bool: + return is_junction(network, node) + +@router.get("/isreservoir/") +async def fastapi_is_reservoir(network: str, node: str) -> bool: + return is_reservoir(network, node) + +@router.get("/istank/") +async def fastapi_is_tank(network: str, node: str) -> bool: + return is_tank(network, node) + +@router.get("/islink/") +async def fastapi_is_link(network: str, link: str) -> bool: + return is_link(network, link) + +@router.get("/ispipe/") +async def fastapi_is_pipe(network: str, link: str) -> bool: + return is_pipe(network, link) + +@router.get("/ispump/") +async def fastapi_is_pump(network: str, link: str) -> bool: + return is_pump(network, link) + +@router.get("/isvalve/") +async def fastapi_is_valve(network: str, link: str) -> bool: + return is_valve(network, link) + +@router.get("/getnodetype/") +async def fastapi_get_node_type(network: str, node: str) -> str: + return get_node_type(network, node) + +@router.get("/getlinktype/") +async def fastapi_get_link_type(network: str, link: str) -> str: + return get_link_type(network, link) + +@router.get("/getelementtype/") +async def fastapi_get_element_type(network: str, element: str) -> str: + return get_element_type(network, element) + +@router.get("/getelementtypevalue/") +async def fastapi_get_element_type_value(network: str, element: str) -> int: + return get_element_type_value(network, element) + +@router.get("/getnodes/") +async def fastapi_get_nodes(network: str) -> list[str]: + return get_nodes(network) + +@router.get("/getlinks/") +async def fastapi_get_links(network: str) -> list[str]: + return get_links(network) + +@router.get("/getnodelinks/") +def get_node_links_endpoint(network: str, node: str) -> list[str]: + return get_node_links(network, node) + +############################################################ +# Node & Link properties +############################################################ + +@router.get("/getnodeproperties/") +async def fast_get_node_properties(network: str, node: str) -> dict[str, Any]: + return get_node_properties(network, node) + +@router.get("/getlinkproperties/") +async def fast_get_link_properties(network: str, link: str) -> dict[str, Any]: + return get_link_properties(network, link) + +@router.get("/getscadaproperties/") +async def fast_get_scada_properties(network: str, scada: str) -> dict[str, Any]: + return get_scada_info(network, scada) + +@router.get("/getallscadaproperties/") +async def fast_get_all_scada_properties(network: str) -> list[dict[str, Any]]: + return get_all_scada_info(network) + +@router.get("/getelementpropertieswithtype/") +async def fast_get_element_properties_with_type( + network: str, elementtype: str, element: str +) -> dict[str, Any]: + return get_element_properties_with_type(network, elementtype, element) + +@router.get("/getelementproperties/") +async def fast_get_element_properties(network: str, element: str) -> dict[str, Any]: + return get_element_properties(network, element) + +############################################################ +# title 1.[TITLE] +############################################################ + +@router.get("/gettitleschema/") +async def fast_get_title_schema(network: str) -> dict[str, dict[str, Any]]: + return get_title_schema(network) + +@router.get("/gettitle/") +async def fast_get_title(network: str) -> dict[str, Any]: + return get_title(network) + +@router.get("/settitle/", response_model=None) +async def fastapi_set_title(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_title(network, ChangeSet(props)) + +############################################################ +# status 10.[STATUS] +############################################################ + +@router.get("/getstatusschema") +async def fastapi_get_status_schema(network: str) -> dict[str, dict[str, Any]]: + return get_status_schema(network) + +@router.get("/getstatus/") +async def fastapi_get_status(network: str, link: str) -> dict[str, Any]: + return get_status(network, link) + +@router.post("/setstatus/", response_model=None) +async def fastapi_set_status_properties( + network: str, link: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"link": link} | props + return set_status(network, ChangeSet(ps)) + +############################################################ +# General Deletion +############################################################ + +@router.post("/deletenode/", response_model=None) +async def fastapi_delete_node(network: str, node: str) -> ChangeSet: + ps = {"id": node} + if is_junction(network, node): + return delete_junction(network, ChangeSet(ps)) + elif is_reservoir(network, node): + return delete_reservoir(network, ChangeSet(ps)) + elif is_tank(network, node): + return delete_tank(network, ChangeSet(ps)) + return ChangeSet() # Should probably raise error or return empty + +@router.post("/deletelink/", response_model=None) +async def fastapi_delete_link(network: str, link: str) -> ChangeSet: + ps = {"id": link} + if is_pipe(network, link): + return delete_pipe(network, ChangeSet(ps)) + elif is_pump(network, link): + return delete_pump(network, ChangeSet(ps)) + elif is_valve(network, link): + return delete_valve(network, ChangeSet(ps)) + return ChangeSet() diff --git a/app/api/v1/endpoints/network/geometry.py b/app/api/v1/endpoints/network/geometry.py new file mode 100644 index 0000000..9b4e555 --- /dev/null +++ b/app/api/v1/endpoints/network/geometry.py @@ -0,0 +1,89 @@ +from fastapi import APIRouter, Request, Depends +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + get_all_scada_info, + get_major_node_coords, + get_major_pipe_nodes, + get_network_in_extent, + get_network_link_nodes, + get_network_node_coords, + get_node_coord, +) +from app.auth.dependencies import get_current_user as verify_token +from app.infra.cache.redis_client import redis_client, encode_datetime, decode_datetime +import msgpack + +router = APIRouter() + +############################################################ +# coord 24.[COORDINATES] +############################################################ + +# @router.get("/getcoordschema/") +# async def fastapi_get_coord_schema(network: str) -> dict[str, dict[str, Any]]: +# return get_coord_schema(network) + +# @router.get("/getcoord/") +# async def fastapi_get_coord(network: str, node: str) -> dict[str, Any]: +# return get_coord(network, node) + +# # example: set_coord(p, ChangeSet({'node': 'j1', 'x': 1.0, 'y': 2.0})) +# @router.post("/setcoord/", response_model=None) +# async def fastapi_set_coord(network: str, req: Request) -> ChangeSet: +# props = await req.json() +# return set_coord(network, ChangeSet(props)) + +@router.get("/getnodecoord/") +async def fastapi_get_node_coord(network: str, node: str) -> dict[str, float] | None: + return get_node_coord(network, node) + +# Additional geometry queries found in main.py logic (implicit or explicit) +@router.get("/getnetworkinextent/") +async def fastapi_get_network_in_extent( + network: str, x1: float, y1: float, x2: float, y2: float +) -> dict[str, Any]: + return get_network_in_extent(network, x1, y1, x2, y2) + +@router.get("/getnetworkgeometries/", dependencies=[Depends(verify_token)]) +async def fastapi_get_network_geometries(network: str) -> dict[str, Any] | None: + cache_key = f"getnetworkgeometries_{network}" + data = redis_client.get(cache_key) + if data: + loaded_dict = msgpack.unpackb(data, object_hook=decode_datetime) + return loaded_dict + + coords = get_network_node_coords(network) + nodes = [] + for node_id, coord in coords.items(): + nodes.append(f"{node_id}:{coord['type']}:{coord['x']}:{coord['y']}") + links = get_network_link_nodes(network) + scadas = get_all_scada_info(network) + + results = {"nodes": nodes, "links": links, "scadas": scadas} + redis_client.set(cache_key, msgpack.packb(results, default=encode_datetime)) + return results + +@router.get("/getmajornodecoords/") +async def fastapi_get_majornode_coords( + network: str, diameter: int +) -> dict[str, dict[str, float]]: + return get_major_node_coords(network, diameter) + +@router.get("/getmajorpipenodes/") +async def fastapi_get_major_pipe_nodes(network: str, diameter: int) -> list[str] | None: + return get_major_pipe_nodes(network, diameter) + +@router.get("/getnetworklinknodes/") +async def fastapi_get_network_link_nodes(network: str) -> list[str] | None: + return get_network_link_nodes(network) + +# @router.get("/getallcoords/") +# async def fastapi_get_all_coords(network: str) -> list[Any]: +# return get_all_coords(network) + +# @router.get("/projectcoordinates/") +# async def fastapi_project_coordinates( +# network: str, from_epsg: int, to_epsg: int +# ) -> ChangeSet: +# return project_coordinates(network, from_epsg, to_epsg) diff --git a/app/api/v1/endpoints/network/junctions.py b/app/api/v1/endpoints/network/junctions.py new file mode 100644 index 0000000..c306099 --- /dev/null +++ b/app/api/v1/endpoints/network/junctions.py @@ -0,0 +1,120 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_junction, + delete_junction, + get_all_junctions, + get_junction, + get_junction_schema, + set_junction, +) + +router = APIRouter() + +@router.get("/getjunctionschema") +async def fast_get_junction_schema(network: str) -> dict[str, dict[str, Any]]: + return get_junction_schema(network) + +@router.post("/addjunction/", response_model=None) +async def fastapi_add_junction( + network: str, junction: str, x: float, y: float, z: float +) -> ChangeSet: + ps = {"id": junction, "x": x, "y": y, "elevation": z} + return add_junction(network, ChangeSet(ps)) + +@router.post("/deletejunction/", response_model=None) +async def fastapi_delete_junction(network: str, junction: str) -> ChangeSet: + ps = {"id": junction} + return delete_junction(network, ChangeSet(ps)) + +@router.get("/getjunctionelevation/") +async def fastapi_get_junction_elevation(network: str, junction: str) -> float: + ps = get_junction(network, junction) + return ps["elevation"] + +@router.get("/getjunctionx/") +async def fastapi_get_junction_x(network: str, junction: str) -> float: + ps = get_junction(network, junction) + return ps["x"] + +@router.get("/getjunctiony/") +async def fastapi_get_junction_y(network: str, junction: str) -> float: + ps = get_junction(network, junction) + return ps["y"] + +@router.get("/getjunctioncoord/") +async def fastapi_get_junction_coord(network: str, junction: str) -> dict[str, float]: + ps = get_junction(network, junction) + coord = {"x": ps["x"], "y": ps["y"]} + return coord + +@router.get("/getjunctiondemand/") +async def fastapi_get_junction_demand(network: str, junction: str) -> float: + ps = get_junction(network, junction) + return ps["demand"] + +@router.get("/getjunctionpattern/") +async def fastapi_get_junction_pattern(network: str, junction: str) -> str: + ps = get_junction(network, junction) + return ps["pattern"] + +@router.post("/setjunctionelevation/", response_model=None) +async def fastapi_set_junction_elevation( + network: str, junction: str, elevation: float +) -> ChangeSet: + ps = {"id": junction, "elevation": elevation} + return set_junction(network, ChangeSet(ps)) + +@router.post("/setjunctionx/", response_model=None) +async def fastapi_set_junction_x(network: str, junction: str, x: float) -> ChangeSet: + ps = {"id": junction, "x": x} + return set_junction(network, ChangeSet(ps)) + +@router.post("/setjunctiony/", response_model=None) +async def fastapi_set_junction_y(network: str, junction: str, y: float) -> ChangeSet: + ps = {"id": junction, "y": y} + return set_junction(network, ChangeSet(ps)) + +@router.post("/setjunctioncoord/", response_model=None) +async def fastapi_set_junction_coord( + network: str, junction: str, x: float, y: float +) -> ChangeSet: + ps = {"id": junction, "x": x, "y": y} + return set_junction(network, ChangeSet(ps)) + +@router.post("/setjunctiondemand/", response_model=None) +async def fastapi_set_junction_demand( + network: str, junction: str, demand: float +) -> ChangeSet: + ps = {"id": junction, "demand": demand} + return set_junction(network, ChangeSet(ps)) + +@router.post("/setjunctionpattern/", response_model=None) +async def fastapi_set_junction_pattern( + network: str, junction: str, pattern: str +) -> ChangeSet: + ps = {"id": junction, "pattern": pattern} + return set_junction(network, ChangeSet(ps)) + +@router.get("/getjunctionproperties/") +async def fastapi_get_junction_properties( + network: str, junction: str +) -> dict[str, Any]: + return get_junction(network, junction) + +@router.get("/getalljunctionproperties/") +async def fastapi_get_all_junction_properties(network: str) -> list[dict[str, Any]]: + # 缓存查询结果提高性能 + # global redis_client # Redis logic removed for clean split, can be re-added if needed or imported + results = get_all_junctions(network) + return results + +@router.post("/setjunctionproperties/", response_model=None) +async def fastapi_set_junction_properties( + network: str, junction: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": junction} | props + return set_junction(network, ChangeSet(ps)) diff --git a/app/api/v1/endpoints/network/pipes.py b/app/api/v1/endpoints/network/pipes.py new file mode 100644 index 0000000..ff01786 --- /dev/null +++ b/app/api/v1/endpoints/network/pipes.py @@ -0,0 +1,143 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + PIPE_STATUS_OPEN, + add_pipe, + delete_pipe, + get_all_pipes, + get_pipe, + get_pipe_schema, + set_pipe, +) + +router = APIRouter() + +@router.get("/getpipeschema") +async def fastapi_get_pipe_schema(network: str) -> dict[str, dict[str, Any]]: + return get_pipe_schema(network) + +@router.post("/addpipe/", response_model=None) +async def fastapi_add_pipe( + network: str, + pipe: str, + node1: str, + node2: str, + length: float = 0, + diameter: float = 0, + roughness: float = 0, + minor_loss: float = 0, + status: str = PIPE_STATUS_OPEN, +) -> ChangeSet: + ps = { + "id": pipe, + "node1": node1, + "node2": node2, + "length": length, + "diameter": diameter, + "roughness": roughness, + "minor_loss": minor_loss, + "status": status, + } + return add_pipe(network, ChangeSet(ps)) + +@router.post("/deletepipe/", response_model=None) +async def fastapi_delete_pipe(network: str, pipe: str) -> ChangeSet: + ps = {"id": pipe} + return delete_pipe(network, ChangeSet(ps)) + +@router.get("/getpipenode1/") +async def fastapi_get_pipe_node1(network: str, pipe: str) -> str | None: + ps = get_pipe(network, pipe) + return ps["node1"] + +@router.get("/getpipenode2/") +async def fastapi_get_pipe_node2(network: str, pipe: str) -> str | None: + ps = get_pipe(network, pipe) + return ps["node2"] + +@router.get("/getpipelength/") +async def fastapi_get_pipe_length(network: str, pipe: str) -> float | None: + ps = get_pipe(network, pipe) + return ps["length"] + +@router.get("/getpipediameter/") +async def fastapi_get_pipe_diameter(network: str, pipe: str) -> float | None: + ps = get_pipe(network, pipe) + return ps["diameter"] + +@router.get("/getpiperoughness/") +async def fastapi_get_pipe_roughness(network: str, pipe: str) -> float | None: + ps = get_pipe(network, pipe) + return ps["roughness"] + +@router.get("/getpipeminorloss/") +async def fastapi_get_pipe_minor_loss(network: str, pipe: str) -> float | None: + ps = get_pipe(network, pipe) + return ps["minor_loss"] + +@router.get("/getpipestatus/") +async def fastapi_get_pipe_status(network: str, pipe: str) -> str | None: + ps = get_pipe(network, pipe) + return ps["status"] + +@router.post("/setpipenode1/", response_model=None) +async def fastapi_set_pipe_node1(network: str, pipe: str, node1: str) -> ChangeSet: + ps = {"id": pipe, "node1": node1} + return set_pipe(network, ChangeSet(ps)) + +@router.post("/setpipenode2/", response_model=None) +async def fastapi_set_pipe_node2(network: str, pipe: str, node2: str) -> ChangeSet: + ps = {"id": pipe, "node2": node2} + return set_pipe(network, ChangeSet(ps)) + +@router.post("/setpipelength/", response_model=None) +async def fastapi_set_pipe_length(network: str, pipe: str, length: float) -> ChangeSet: + ps = {"id": pipe, "length": length} + return set_pipe(network, ChangeSet(ps)) + +@router.post("/setpipediameter/", response_model=None) +async def fastapi_set_pipe_diameter( + network: str, pipe: str, diameter: float +) -> ChangeSet: + ps = {"id": pipe, "diameter": diameter} + return set_pipe(network, ChangeSet(ps)) + +@router.post("/setpiperoughness/", response_model=None) +async def fastapi_set_pipe_roughness( + network: str, pipe: str, roughness: float +) -> ChangeSet: + ps = {"id": pipe, "roughness": roughness} + return set_pipe(network, ChangeSet(ps)) + +@router.post("/setpipeminorloss/", response_model=None) +async def fastapi_set_pipe_minor_loss( + network: str, pipe: str, minor_loss: float +) -> ChangeSet: + ps = {"id": pipe, "minor_loss": minor_loss} + return set_pipe(network, ChangeSet(ps)) + +@router.post("/setpipestatus/", response_model=None) +async def fastapi_set_pipe_status(network: str, pipe: str, status: str) -> ChangeSet: + ps = {"id": pipe, "status": status} + return set_pipe(network, ChangeSet(ps)) + +@router.get("/getpipeproperties/") +async def fastapi_get_pipe_properties(network: str, pipe: str) -> dict[str, Any]: + return get_pipe(network, pipe) + +@router.get("/getallpipeproperties/") +async def fastapi_get_all_pipe_properties(network: str) -> list[dict[str, Any]]: + # 缓存查询结果提高性能 + # global redis_client + results = get_all_pipes(network) + return results + +@router.post("/setpipeproperties/", response_model=None) +async def fastapi_set_pipe_properties( + network: str, pipe: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": pipe} | props + return set_pipe(network, ChangeSet(ps)) diff --git a/app/api/v1/endpoints/network/pumps.py b/app/api/v1/endpoints/network/pumps.py new file mode 100644 index 0000000..0b63c21 --- /dev/null +++ b/app/api/v1/endpoints/network/pumps.py @@ -0,0 +1,69 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_pump, + delete_pump, + get_all_pumps, + get_pump, + get_pump_schema, + set_pump, +) + +router = APIRouter() + +@router.get("/getpumpschema") +async def fastapi_get_pump_schema(network: str) -> dict[str, dict[str, Any]]: + return get_pump_schema(network) + +@router.post("/addpump/", response_model=None) +async def fastapi_add_pump( + network: str, pump: str, node1: str, node2: str, power: float = 0.0 +) -> ChangeSet: + ps = {"id": pump, "node1": node1, "node2": node2, "power": power} + return add_pump(network, ChangeSet(ps)) + +@router.post("/deletepump/", response_model=None) +async def fastapi_delete_pump(network: str, pump: str) -> ChangeSet: + ps = {"id": pump} + return delete_pump(network, ChangeSet(ps)) + +@router.get("/getpumpnode1/") +async def fastapi_get_pump_node1(network: str, pump: str) -> str | None: + ps = get_pump(network, pump) + return ps["node1"] + +@router.get("/getpumpnode2/") +async def fastapi_get_pump_node2(network: str, pump: str) -> str | None: + ps = get_pump(network, pump) + return ps["node2"] + +@router.post("/setpumpnode1/", response_model=None) +async def fastapi_set_pump_node1(network: str, pump: str, node1: str) -> ChangeSet: + ps = {"id": pump, "node1": node1} + return set_pump(network, ChangeSet(ps)) + +@router.post("/setpumpnode2/", response_model=None) +async def fastapi_set_pump_node2(network: str, pump: str, node2: str) -> ChangeSet: + ps = {"id": pump, "node2": node2} + return set_pump(network, ChangeSet(ps)) + +@router.get("/getpumpproperties/") +async def fastapi_get_pump_properties(network: str, pump: str) -> dict[str, Any]: + return get_pump(network, pump) + +@router.get("/getallpumpproperties/") +async def fastapi_get_all_pump_properties(network: str) -> list[dict[str, Any]]: + # 缓存查询结果提高性能 + # global redis_client + results = get_all_pumps(network) + return results + +@router.post("/setpumpproperties/", response_model=None) +async def fastapi_set_pump_properties( + network: str, pump: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": pump} | props + return set_pump(network, ChangeSet(ps)) diff --git a/app/api/v1/endpoints/network/regions.py b/app/api/v1/endpoints/network/regions.py new file mode 100644 index 0000000..6c957b3 --- /dev/null +++ b/app/api/v1/endpoints/network/regions.py @@ -0,0 +1,281 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_district_metering_area, + add_region, + add_service_area, + add_virtual_district, + calculate_district_metering_area_for_network, + calculate_district_metering_area_for_nodes, + calculate_district_metering_area_for_region, + calculate_service_area, + calculate_virtual_district, + delete_district_metering_area, + delete_region, + delete_service_area, + delete_virtual_district, + generate_district_metering_area, + generate_service_area, + generate_sub_district_metering_area, + generate_virtual_district, + get_all_district_metering_area_ids, + get_all_district_metering_areas, + get_all_service_areas, + get_all_virtual_districts, + get_district_metering_area, + get_district_metering_area_schema, + get_region, + get_region_schema, + get_service_area, + get_service_area_schema, + get_virtual_district, + get_virtual_district_schema, + set_district_metering_area, + set_region, + set_service_area, + set_virtual_district, +) + +router = APIRouter() + +############################################################ +# region 32 +############################################################ + +@router.get("/calculateregion/") +async def fastapi_calculate_region(network: str, time_index: int) -> dict[str, Any]: + return calculate_region(network, time_index) + +@router.get("/getregionschema/") +async def fastapi_get_region_schema(network: str) -> dict[str, dict[str, Any]]: + return get_region_schema(network) + +@router.get("/getregion/") +async def fastapi_get_region(network: str, id: str) -> dict[str, Any]: + return get_region(network, id) + +@router.post("/setregion/", response_model=None) +async def fastapi_set_region(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_region(network, ChangeSet(props)) + +@router.post("/addregion/", response_model=None) +async def fastapi_add_region(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_region(network, ChangeSet(props)) + +@router.post("/deleteregion/", response_model=None) +async def fastapi_delete_region(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_region(network, ChangeSet(props)) + +@router.get("/getallregions/") +async def fastapi_get_all_regions(network: str) -> list[dict[str, Any]]: + return get_all_regions(network) + +@router.post("/generateregion/", response_model=None) +async def fastapi_generate_region( + network: str, inflate_delta: float +) -> ChangeSet: + return generate_region(network, inflate_delta) + + +############################################################ +# district_metering_area 33 +############################################################ + +@router.get("/calculatedistrictmeteringarea/") +async def fastapi_calculate_district_metering_area( + network: str, req: Request +) -> list[list[str]]: + props = await req.json() + nodes = props["nodes"] + part_count = props["part_count"] + part_type = props["part_type"] + return calculate_district_metering_area( + network, nodes, part_count, part_type + ) + +@router.get("/calculatedistrictmeteringareaforregion/") +async def fastapi_calculate_district_metering_area_for_region( + network: str, req: Request +) -> list[list[str]]: + props = await req.json() + region = props["region"] + part_count = props["part_count"] + part_type = props["part_type"] + return calculate_district_metering_area_for_region( + network, region, part_count, part_type + ) + +@router.get("/calculatedistrictmeteringareafornetwork/") +async def fastapi_calculate_district_metering_area_for_network( + network: str, req: Request +) -> list[list[str]]: + props = await req.json() + part_count = props["part_count"] + part_type = props["part_type"] + return calculate_district_metering_area_for_network(network, part_count, part_type) + +@router.get("/getdistrictmeteringareaschema/") +async def fastapi_get_district_metering_area_schema( + network: str, +) -> dict[str, dict[str, Any]]: + return get_district_metering_area_schema(network) + +@router.get("/getdistrictmeteringarea/") +async def fastapi_get_district_metering_area(network: str, id: str) -> dict[str, Any]: + return get_district_metering_area(network, id) + +@router.post("/setdistrictmeteringarea/", response_model=None) +async def fastapi_set_district_metering_area(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_district_metering_area(network, ChangeSet(props)) + +@router.post("/adddistrictmeteringarea/", response_model=None) +async def fastapi_add_district_metering_area(network: str, req: Request) -> ChangeSet: + props = await req.json() + # boundary should be [(x,y), (x,y)] + boundary = props.get("boundary", []) + newBoundary = [] + for pt in boundary: + if len(pt) >= 2: + newBoundary.append((pt[0], pt[1])) + props["boundary"] = newBoundary + return add_district_metering_area(network, ChangeSet(props)) + +@router.post("/deletedistrictmeteringarea/", response_model=None) +async def fastapi_delete_district_metering_area( + network: str, req: Request +) -> ChangeSet: + props = await req.json() + return delete_district_metering_area(network, ChangeSet(props)) + +@router.get("/getalldistrictmeteringareaids/") +async def fastapi_get_all_district_metering_area_ids(network: str) -> list[str]: + return get_all_district_metering_area_ids(network) + +@router.get("/getalldistrictmeteringareas/") +async def getalldistrictmeteringareas(network: str) -> list[dict[str, Any]]: + return get_all_district_metering_areas(network) + +@router.post("/generatedistrictmeteringarea/", response_model=None) +async def fastapi_generate_district_metering_area( + network: str, part_count: int, part_type: int, inflate_delta: float +) -> ChangeSet: + return generate_district_metering_area( + network, part_count, part_type, inflate_delta + ) + +@router.post("/generatesubdistrictmeteringarea/", response_model=None) +async def fastapi_generate_sub_district_metering_area( + network: str, dma: str, part_count: int, part_type: int, inflate_delta: float +) -> ChangeSet: + return generate_sub_district_metering_area( + network, dma, part_count, part_type, inflate_delta + ) + + +############################################################ +# service_area 34 +############################################################ + +@router.get("/calculateservicearea/") +async def fastapi_calculate_service_area( + network: str, time_index: int +) -> dict[str, Any]: + return calculate_service_area(network, time_index) + +@router.get("/getserviceareaschema/") +async def fastapi_get_service_area_schema(network: str) -> dict[str, dict[str, Any]]: + return get_service_area_schema(network) + +@router.get("/getservicearea/") +async def fastapi_get_service_area(network: str, id: str) -> dict[str, Any]: + return get_service_area(network, id) + +@router.post("/setservicearea/", response_model=None) +async def fastapi_set_service_area(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_service_area(network, ChangeSet(props)) + +@router.post("/addservicearea/", response_model=None) +async def fastapi_add_service_area(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_service_area(network, ChangeSet(props)) + +@router.post("/deleteservicearea/", response_model=None) +async def fastapi_delete_service_area(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_service_area(network, ChangeSet(props)) + +@router.get("/getallserviceareas/") +async def fastapi_get_all_service_areas(network: str) -> list[dict[str, Any]]: + return get_all_service_areas(network) + +@router.post("/generateservicearea/", response_model=None) +async def fastapi_generate_service_area( + network: str, inflate_delta: float +) -> ChangeSet: + return generate_service_area(network, inflate_delta) + + +############################################################ +# virtual_district 35 +############################################################ + +@router.get("/calculatevirtualdistrict/") +async def fastapi_calculate_virtual_district( + network: str, centers: list[str] +) -> dict[str, list[Any]]: + return calculate_virtual_district(network, centers) + +@router.get("/getvirtualdistrictschema/") +async def fastapi_get_virtual_district_schema( + network: str, +) -> dict[str, dict[str, Any]]: + return get_virtual_district_schema(network) + +@router.get("/getvirtualdistrict/") +async def fastapi_get_virtual_district(network: str, id: str) -> dict[str, Any]: + return get_virtual_district(network, id) + +@router.post("/setvirtualdistrict/", response_model=None) +async def fastapi_set_virtual_district(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_virtual_district(network, ChangeSet(props)) + +@router.post("/addvirtualdistrict/", response_model=None) +async def fastapi_add_virtual_district(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_virtual_district(network, ChangeSet(props)) + +@router.post("/deletevirtualdistrict/", response_model=None) +async def fastapi_delete_virtual_district(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_virtual_district(network, ChangeSet(props)) + +@router.get("/getallvirtualdistrict/") +async def fastapi_get_all_virtual_district(network: str) -> list[dict[str, Any]]: + return get_all_virtual_districts(network) + +@router.post("/generatevirtualdistrict/", response_model=None) +async def fastapi_generate_virtual_district( + network: str, inflate_delta: float, req: Request +) -> ChangeSet: + props = await req.json() + return generate_virtual_district(network, props["centers"], inflate_delta) + +@router.get("/calculatedistrictmeteringareafornodes/") +async def fastapi_calculate_district_metering_area_for_nodes( + network: str, req: Request +) -> list[list[str]]: + props = await req.json() + nodes = props["nodes"] + part_count = props["part_count"] + part_type = props["part_type"] + return calculate_district_metering_area_for_nodes( + network, nodes, part_count, part_type + ) diff --git a/app/api/v1/endpoints/network/reservoirs.py b/app/api/v1/endpoints/network/reservoirs.py new file mode 100644 index 0000000..0973882 --- /dev/null +++ b/app/api/v1/endpoints/network/reservoirs.py @@ -0,0 +1,114 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_reservoir, + delete_reservoir, + get_all_reservoirs, + get_reservoir, + get_reservoir_schema, + set_reservoir, +) + +router = APIRouter() + +@router.get("/getreservoirschema") +async def fast_get_reservoir_schema(network: str) -> dict[str, dict[str, Any]]: + return get_reservoir_schema(network) + +@router.post("/addreservoir/", response_model=None) +async def fastapi_add_reservoir( + network: str, reservoir: str, x: float, y: float, head: float +) -> ChangeSet: + ps = {"id": reservoir, "x": x, "y": y, "head": head} + return add_reservoir(network, ChangeSet(ps)) + +@router.post("/deletereservoir/", response_model=None) +async def fastapi_delete_reservoir(network: str, reservoir: str) -> ChangeSet: + ps = {"id": reservoir} + return delete_reservoir(network, ChangeSet(ps)) + +@router.get("/getreservoirhead/") +async def fastapi_get_reservoir_head(network: str, reservoir: str) -> float | None: + ps = get_reservoir(network, reservoir) + return ps["head"] + +@router.get("/getreservoirpattern/") +async def fastapi_get_reservoir_pattern(network: str, reservoir: str) -> str | None: + ps = get_reservoir(network, reservoir) + return ps["pattern"] + +@router.get("/getreservoirx/") +async def fastapi_get_reservoir_x( + network: str, reservoir: str +) -> dict[str, float] | None: + ps = get_reservoir(network, reservoir) + return ps["x"] + +@router.get("/getreservoiry/") +async def fastapi_get_reservoir_y( + network: str, reservoir: str +) -> dict[str, float] | None: + ps = get_reservoir(network, reservoir) + return ps["y"] + +@router.get("/getreservoircoord/") +async def fastapi_get_reservoir_coord( + network: str, reservoir: str +) -> dict[str, float] | None: + ps = get_reservoir(network, reservoir) + coord = {"id": reservoir, "x": ps["x"], "y": ps["y"]} + return coord + +@router.post("/setreservoirhead/", response_model=None) +async def fastapi_set_reservoir_head( + network: str, reservoir: str, head: float +) -> ChangeSet: + ps = {"id": reservoir, "head": head} + return set_reservoir(network, ChangeSet(ps)) + +@router.post("/setreservoirpattern/", response_model=None) +async def fastapi_set_reservoir_pattern( + network: str, reservoir: str, pattern: str +) -> ChangeSet: + ps = {"id": reservoir, "pattern": pattern} + return set_reservoir(network, ChangeSet(ps)) + +@router.post("/setreservoirx/", response_model=None) +async def fastapi_set_reservoir_x(network: str, reservoir: str, x: float) -> ChangeSet: + ps = {"id": reservoir, "x": x} + return set_reservoir(network, ChangeSet(ps)) + +@router.post("/setreservoiry/", response_model=None) +async def fastapi_set_reservoir_y(network: str, reservoir: str, y: float) -> ChangeSet: + ps = {"id": reservoir, "y": y} + return set_reservoir(network, ChangeSet(ps)) + +@router.post("/setreservoircoord/", response_model=None) +async def fastapi_set_reservoir_coord( + network: str, reservoir: str, x: float, y: float +) -> ChangeSet: + ps = {"id": reservoir, "x": x, "y": y} + return set_reservoir(network, ChangeSet(ps)) + +@router.get("/getreservoirproperties/") +async def fastapi_get_reservoir_properties( + network: str, reservoir: str +) -> dict[str, Any]: + return get_reservoir(network, reservoir) + +@router.get("/getallreservoirproperties/") +async def fastapi_get_all_reservoir_properties(network: str) -> list[dict[str, Any]]: + # 缓存查询结果提高性能 + # global redis_client + results = get_all_reservoirs(network) + return results + +@router.post("/setreservoirproperties/", response_model=None) +async def fastapi_set_reservoir_properties( + network: str, reservoir: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": reservoir} | props + return set_reservoir(network, ChangeSet(ps)) diff --git a/app/api/v1/endpoints/network/tags.py b/app/api/v1/endpoints/network/tags.py new file mode 100644 index 0000000..7a63828 --- /dev/null +++ b/app/api/v1/endpoints/network/tags.py @@ -0,0 +1,34 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + get_tag, + get_tag_schema, + get_tags, + set_tag, +) + +router = APIRouter() + +############################################################ +# tag 8.[TAGS] +############################################################ + +@router.get("/gettagschema/") +async def fastapi_get_tag_schema(network: str) -> dict[str, dict[str, Any]]: + return get_tag_schema(network) + +@router.get("/gettag/") +async def fastapi_get_tag(network: str, t_type: str, id: str) -> dict[str, Any]: + return get_tag(network, t_type, id) + +@router.get("/gettags/") +async def fastapi_get_tags(network: str) -> list[dict[str, Any]]: + tags = get_tags(network) + return tags + +@router.post("/settag/", response_model=None) +async def fastapi_set_tag(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_tag(network, ChangeSet(props)) diff --git a/app/api/v1/endpoints/network/tanks.py b/app/api/v1/endpoints/network/tanks.py new file mode 100644 index 0000000..1696b1b --- /dev/null +++ b/app/api/v1/endpoints/network/tanks.py @@ -0,0 +1,197 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + add_tank, + delete_tank, + get_all_tanks, + get_tank, + get_tank_schema, + set_tank, +) + +router = APIRouter() + +@router.get("/gettankschema") +async def fast_get_tank_schema(network: str) -> dict[str, dict[str, Any]]: + return get_tank_schema(network) + +@router.post("/addtank/", response_model=None) +async def fastapi_add_tank( + network: str, + tank: str, + x: float, + y: float, + elevation: float, + init_level: float = 0, + min_level: float = 0, + max_level: float = 0, + diameter: float = 0, + min_vol: float = 0, +) -> ChangeSet: + ps = { + "id": tank, + "x": x, + "y": y, + "elevation": elevation, + "init_level": init_level, + "min_level": min_level, + "max_level": max_level, + "diameter": diameter, + "min_vol": min_vol, + } + return add_tank(network, ChangeSet(ps)) + +@router.post("/deletetank/", response_model=None) +async def fastapi_delete_tank(network: str, tank: str) -> ChangeSet: + ps = {"id": tank} + return delete_tank(network, ChangeSet(ps)) + +@router.get("/gettankelevation/") +async def fastapi_get_tank_elevation(network: str, tank: str) -> float | None: + ps = get_tank(network, tank) + return ps["elevation"] + +@router.get("/gettankinitlevel/") +async def fastapi_get_tank_init_level(network: str, tank: str) -> float | None: + ps = get_tank(network, tank) + return ps["init_level"] + +@router.get("/gettankminlevel/") +async def fastapi_get_tank_min_level(network: str, tank: str) -> float | None: + ps = get_tank(network, tank) + return ps["min_level"] + +@router.get("/gettankmaxlevel/") +async def fastapi_get_tank_max_level(network: str, tank: str) -> float | None: + ps = get_tank(network, tank) + return ps["max_level"] + +@router.get("/gettankdiameter/") +async def fastapi_get_tank_diameter(network: str, tank: str) -> float | None: + ps = get_tank(network, tank) + return ps["diameter"] + +@router.get("/gettankminvol/") +async def fastapi_get_tank_min_vol(network: str, tank: str) -> float | None: + ps = get_tank(network, tank) + return ps["min_vol"] + +@router.get("/gettankvolcurve/") +async def fastapi_get_tank_vol_curve(network: str, tank: str) -> str | None: + ps = get_tank(network, tank) + return ps["vol_curve"] + +@router.get("/gettankoverflow/") +async def fastapi_get_tank_overflow(network: str, tank: str) -> str | None: + ps = get_tank(network, tank) + return ps["overflow"] + +@router.get("/gettankx/") +async def fastapi_get_tank_x(network: str, tank: str) -> float: + ps = get_tank(network, tank) + return ps["x"] + +@router.get("/gettanky/") +async def fastapi_get_tank_y(network: str, tank: str) -> float: + ps = get_tank(network, tank) + return ps["y"] + +@router.get("/gettankcoord/") +async def fastapi_get_tank_coord(network: str, tank: str) -> dict[str, float]: + ps = get_tank(network, tank) + coord = {"x": ps["x"], "y": ps["y"]} + return coord + +@router.post("/settankelevation/", response_model=None) +async def fastapi_set_tank_elevation( + network: str, tank: str, elevation: float +) -> ChangeSet: + ps = {"id": tank, "elevation": elevation} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankinitlevel/", response_model=None) +async def fastapi_set_tank_init_level( + network: str, tank: str, init_level: float +) -> ChangeSet: + ps = {"id": tank, "init_level": init_level} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankminlevel/", response_model=None) +async def fastapi_set_tank_min_level( + network: str, tank: str, min_level: float +) -> ChangeSet: + ps = {"id": tank, "min_level": min_level} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankmaxlevel/", response_model=None) +async def fastapi_set_tank_max_level( + network: str, tank: str, max_level: float +) -> ChangeSet: + ps = {"id": tank, "max_level": max_level} + return set_tank(network, ChangeSet(ps)) + +@router.post("settankdiameter//", response_model=None) +async def fastapi_set_tank_diameter( + network: str, tank: str, diameter: float +) -> ChangeSet: + ps = {"id": tank, "diameter": diameter} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankminvol/", response_model=None) +async def fastapi_set_tank_min_vol( + network: str, tank: str, min_vol: float +) -> ChangeSet: + ps = {"id": tank, "min_vol": min_vol} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankvolcurve/", response_model=None) +async def fastapi_set_tank_vol_curve( + network: str, tank: str, vol_curve: str +) -> ChangeSet: + ps = {"id": tank, "vol_curve": vol_curve} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankoverflow/", response_model=None) +async def fastapi_set_tank_overflow( + network: str, tank: str, overflow: str +) -> ChangeSet: + ps = {"id": tank, "overflow": overflow} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankx/", response_model=None) +async def fastapi_set_tank_x(network: str, tank: str, x: float) -> ChangeSet: + ps = {"id": tank, "x": x} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settanky/", response_model=None) +async def fastapi_set_tank_y(network: str, tank: str, y: float) -> ChangeSet: + ps = {"id": tank, "y": y} + return set_tank(network, ChangeSet(ps)) + +@router.post("/settankcoord/", response_model=None) +async def fastapi_set_tank_coord( + network: str, tank: str, x: float, y: float +) -> ChangeSet: + ps = {"id": tank, "x": x, "y": y} + return set_tank(network, ChangeSet(ps)) + +@router.get("/gettankproperties/") +async def fastapi_get_tank_properties(network: str, tank: str) -> dict[str, Any]: + return get_tank(network, tank) + +@router.get("/getalltankproperties/") +async def fastapi_get_all_tank_properties(network: str) -> list[dict[str, Any]]: + # 缓存查询结果提高性能 + # global redis_client + results = get_all_tanks(network) + return results + +@router.post("/settankproperties/", response_model=None) +async def fastapi_set_tank_properties( + network: str, tank: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": tank} | props + return set_tank(network, ChangeSet(ps)) diff --git a/app/api/v1/endpoints/network/valves.py b/app/api/v1/endpoints/network/valves.py new file mode 100644 index 0000000..5b7f258 --- /dev/null +++ b/app/api/v1/endpoints/network/valves.py @@ -0,0 +1,125 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import ( + Any, + ChangeSet, + VALVES_TYPE_PRV, + add_valve, + delete_valve, + get_all_valves, + get_valve, + get_valve_schema, + set_valve, +) + +router = APIRouter() + +@router.get("/getvalveschema") +async def fastapi_get_valve_schema(network: str) -> dict[str, dict[str, Any]]: + return get_valve_schema(network) + +@router.post("/addvalve/", response_model=None) +async def fastapi_add_valve( + network: str, + valve: str, + node1: str, + node2: str, + diameter: float = 0, + v_type: str = VALVES_TYPE_PRV, + setting: float = 0, + minor_loss: float = 0, +) -> ChangeSet: + ps = { + "id": valve, + "node1": node1, + "node2": node2, + "diameter": diameter, + "v_type": v_type, + "setting": setting, + "minor_loss": minor_loss, + } + + return add_valve(network, ChangeSet(ps)) + +@router.post("/deletevalve/", response_model=None) +async def fastapi_delete_valve(network: str, valve: str) -> ChangeSet: + ps = {"id": valve} + return delete_valve(network, ChangeSet(ps)) + +@router.get("/getvalvenode1/") +async def fastapi_get_valve_node1(network: str, valve: str) -> str | None: + ps = get_valve(network, valve) + return ps["node1"] + +@router.get("/getvalvenode2/") +async def fastapi_get_valve_node2(network: str, valve: str) -> str | None: + ps = get_valve(network, valve) + return ps["node2"] + +@router.get("/getvalvediameter/") +async def fastapi_get_valve_diameter(network: str, valve: str) -> float | None: + ps = get_valve(network, valve) + return ps["diameter"] + +@router.get("/getvalvetype/") +async def fastapi_get_valve_type(network: str, valve: str) -> str | None: + ps = get_valve(network, valve) + return ps["type"] + +@router.get("/getvalvesetting/") +async def fastapi_get_valve_setting(network: str, valve: str) -> float | None: + ps = get_valve(network, valve) + return ps["setting"] + +@router.get("/getvalveminorloss/") +async def fastapi_get_valve_minor_loss(network: str, valve: str) -> float | None: + ps = get_valve(network, valve) + return ps["minor_loss"] + +@router.post("/setvalvenode1/", response_model=None) +async def fastapi_set_valve_node1(network: str, valve: str, node1: str) -> ChangeSet: + ps = {"id": valve, "node1": node1} + return set_valve(network, ChangeSet(ps)) + +@router.post("/setvalvenode2/", response_model=None) +async def fastapi_set_valve_node2(network: str, valve: str, node2: str) -> ChangeSet: + ps = {"id": valve, "node2": node2} + return set_valve(network, ChangeSet(ps)) + +@router.post("/setvalvenodediameter/", response_model=None) +async def fastapi_set_valve_diameter( + network: str, valve: str, diameter: float +) -> ChangeSet: + ps = {"id": valve, "diameter": diameter} + return set_valve(network, ChangeSet(ps)) + +@router.post("/setvalvetype/", response_model=None) +async def fastapi_set_valve_type(network: str, valve: str, type: str) -> ChangeSet: + ps = {"id": valve, "type": type} + return set_valve(network, ChangeSet(ps)) + +@router.post("/setvalvesetting/", response_model=None) +async def fastapi_set_valve_setting( + network: str, valve: str, setting: float +) -> ChangeSet: + ps = {"id": valve, "setting": setting} + return set_valve(network, ChangeSet(ps)) + +@router.get("/getvalveproperties/") +async def fastapi_get_valve_properties(network: str, valve: str) -> dict[str, Any]: + return get_valve(network, valve) + +@router.get("/getallvalveproperties/") +async def fastapi_get_all_valve_properties(network: str) -> list[dict[str, Any]]: + # 缓存查询结果提高性能 + # global redis_client + results = get_all_valves(network) + return results + +@router.post("/setvalveproperties/", response_model=None) +async def fastapi_set_valve_properties( + network: str, valve: str, req: Request +) -> ChangeSet: + props = await req.json() + ps = {"id": valve} | props + return set_valve(network, ChangeSet(ps)) diff --git a/app/api/v1/endpoints/network_elements.py b/app/api/v1/endpoints/network_elements.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/endpoints/project.py b/app/api/v1/endpoints/project.py new file mode 100644 index 0000000..8faabe7 --- /dev/null +++ b/app/api/v1/endpoints/project.py @@ -0,0 +1,226 @@ +import json +from fastapi import APIRouter, Request, HTTPException +from fastapi.responses import PlainTextResponse +from typing import Any, Dict +import app.services.project_info as project_info +from app.infra.db.postgresql.database import get_database_instance as get_pg_db +from app.infra.db.timescaledb.database import get_database_instance as get_ts_db +from app.services.tjnetwork import ( + ChangeSet, + list_project, + have_project, + create_project, + delete_project, + is_project_open, + open_project, + close_project, + copy_project, + import_inp, + export_inp, + read_inp, + dump_inp, + get_all_vertices, + get_all_scada_elements, + get_all_district_metering_areas, + get_all_service_areas, + get_all_virtual_districts, + get_extension_data, + convert_inp_v3_to_v2, +) + +# For inp file upload/download +import os +from fastapi import Response, status +from fastapi.responses import FileResponse +inpDir = "data/" # Assuming data directory exists or is defined somewhere. +# In main.py it was likely global. For safety, let's use a relative path or get from config. +# But let's stick to what main.py probably used or a default. + +router = APIRouter() +lockedPrjs: Dict[str, str] = {} + +@router.get("/listprojects/") +async def list_projects_endpoint() -> list[str]: + return list_project() + +@router.get("/haveproject/") +async def have_project_endpoint(network: str): + return have_project(network) + +@router.post("/createproject/") +async def create_project_endpoint(network: str): + create_project(network) + return network + +@router.post("/deleteproject/") +async def delete_project_endpoint(network: str): + delete_project(network) + return True + +@router.get("/isprojectopen/") +async def is_project_open_endpoint(network: str): + return is_project_open(network) + +@router.post("/openproject/") +async def open_project_endpoint(network: str): + open_project(network) + + # 尝试连接指定数据库 + try: + # 初始化 PostgreSQL 连接池 + pg_instance = await get_pg_db(network) + async with pg_instance.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute("SELECT 1") + + # 初始化 TimescaleDB 连接池 + ts_instance = await get_ts_db(network) + async with ts_instance.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute("SELECT 1") + + except Exception as e: + # 记录错误但不阻断项目打开,或者根据需求决定是否阻断 + # 这里选择打印错误,因为 open_project 原本只负责原生部分 + print(f"Failed to connect to databases for {network}: {str(e)}") + # 如果数据库连接是必须的,可以抛出异常: + # raise HTTPException(status_code=500, detail=f"Database connection failed: {str(e)}") + + return network + +@router.post("/closeproject/") +async def close_project_endpoint(network: str): + close_project(network) + return True + +@router.post("/copyproject/") +async def copy_project_endpoint(source: str, target: str): + copy_project(source, target) + return True + +@router.post("/importinp/") +async def import_inp_endpoint(network: str, req: Request): + jo_root = await req.json() + inp_text = jo_root["inp"] + ps = {"inp": inp_text} + ret = import_inp(network, ChangeSet(ps)) + print(ret) + return ret + +@router.get("/exportinp/", response_model=None) +async def export_inp_endpoint(network: str, version: str) -> ChangeSet: + cs = export_inp(network, version) + op = cs.operations[0] + open_project(network) + op["vertex"] = json.dumps(get_all_vertices(network)) + op["scada"] = json.dumps(get_all_scada_elements(network)) + op["dma"] = json.dumps(get_all_district_metering_areas(network)) + op["sa"] = json.dumps(get_all_service_areas(network)) + op["vd"] = json.dumps(get_all_virtual_districts(network)) + op["legend"] = get_extension_data(network, "legend") + + db = get_extension_data(network, "scada_db") + print(db) + scada_db = "" + if db: + scada_db = db + print(scada_db) + op["scada_db"] = scada_db + + close_project(network) + + return cs + +@router.post("/readinp/") +async def read_inp_endpoint(network: str, inp: str) -> bool: + read_inp(network, inp) + return True + +@router.get("/dumpinp/") +async def dump_inp_endpoint(network: str, inp: str) -> bool: + dump_inp(network, inp) + return True + +@router.get("/isprojectlocked/") +async def is_project_locked_endpoint(network: str, req: Request): + return network in lockedPrjs.keys() + +@router.get("/isprojectlockedbyme/") +async def is_project_locked_by_me_endpoint(network: str, req: Request): + client_host = req.client.host + return lockedPrjs.get(network) == client_host + +# 0 successfully locked +# 1 already locked by you +# 2 locked by others +@router.post("/lockproject/") +async def lock_project_endpoint(network: str, req: Request): + client_host = req.client.host + if not network in lockedPrjs.keys(): + lockedPrjs[network] = client_host + return 0 + else: + if lockedPrjs.get(network) == client_host: + return 1 + else: + return 2 + +@router.post("/unlockproject/") +def unlock_project_endpoint(network: str, req: Request): + client_host = req.client.host + if lockedPrjs.get(network) == client_host: + print("delete key") + del lockedPrjs[network] + return True + + return False + +# inp file operations +@router.post("/uploadinp/", status_code=status.HTTP_200_OK) +async def fastapi_upload_inp(afile: bytes, name: str): + if not os.path.exists(inpDir): + os.makedirs(inpDir, exist_ok=True) + + filePath = inpDir + str(name) + with open(filePath, "wb") as f: + f.write(afile) + return True + +@router.get("/downloadinp/", status_code=status.HTTP_200_OK) +async def fastapi_download_inp(name: str, response: Response): + filePath = inpDir + name + if os.path.exists(filePath): + return FileResponse( + filePath, media_type="application/octet-stream", filename="inp.inp" + ) + else: + response.status_code = status.HTTP_400_BAD_REQUEST + return True + +# DingZQ, 2024-12-28, convert v3 to v2 +@router.get("/convertv3tov2/", response_model=None) +async def fastapi_convert_v3_to_v2(req: Request) -> ChangeSet: + network = "v3Tov2" + jo_root = await req.json() + inp = jo_root["inp"] + cs = convert_inp_v3_to_v2(inp) + op = cs.operations[0] + open_project(network) + op["vertex"] = json.dumps(get_all_vertices(network)) + op["scada"] = json.dumps(get_all_scada_elements(network)) + op["dma"] = json.dumps(get_all_district_metering_areas(network)) + op["sa"] = json.dumps(get_all_service_areas(network)) + op["vd"] = json.dumps(get_all_virtual_districts(network)) + op["legend"] = get_extension_data(network, "legend") + + db = get_extension_data(network, "scada_db") + print(db) + scada_db = "" + if db: + scada_db = db + print(scada_db) + op["scada_db"] = scada_db + + close_project(network) + + return cs diff --git a/app/api/v1/endpoints/project_data.py b/app/api/v1/endpoints/project_data.py new file mode 100644 index 0000000..e3ac917 --- /dev/null +++ b/app/api/v1/endpoints/project_data.py @@ -0,0 +1,79 @@ +from fastapi import APIRouter, Depends, HTTPException +from psycopg import AsyncConnection + +from app.infra.db.postgresql.scada_info import ScadaRepository +from app.infra.db.postgresql.scheme import SchemeRepository +from app.auth.project_dependencies import get_project_pg_connection + +router = APIRouter() + + +async def get_database_connection( + conn: AsyncConnection = Depends(get_project_pg_connection), +): + yield conn + + +@router.get("/scada-info") +async def get_scada_info_with_connection( + conn: AsyncConnection = Depends(get_database_connection), +): + """ + 使用连接池查询所有SCADA信息 + """ + try: + scada_data = await ScadaRepository.get_scadas(conn) + return {"success": True, "data": scada_data, "count": len(scada_data)} + except Exception as e: + raise HTTPException( + status_code=500, detail=f"查询SCADA信息时发生错误: {str(e)}" + ) + + +@router.get("/scheme-list") +async def get_scheme_list_with_connection( + conn: AsyncConnection = Depends(get_database_connection), +): + """ + 使用连接池查询所有方案信息 + """ + try: + scheme_data = await SchemeRepository.get_schemes(conn) + return {"success": True, "data": scheme_data, "count": len(scheme_data)} + except Exception as e: + raise HTTPException(status_code=500, detail=f"查询方案信息时发生错误: {str(e)}") + + +@router.get("/burst-locate-result") +async def get_burst_locate_result_with_connection( + conn: AsyncConnection = Depends(get_database_connection), +): + """ + 使用连接池查询所有爆管定位结果 + """ + try: + burst_data = await SchemeRepository.get_burst_locate_results(conn) + return {"success": True, "data": burst_data, "count": len(burst_data)} + except Exception as e: + raise HTTPException( + status_code=500, detail=f"查询爆管定位结果时发生错误: {str(e)}" + ) + + +@router.get("/burst-locate-result/{burst_incident}") +async def get_burst_locate_result_by_incident( + burst_incident: str, + conn: AsyncConnection = Depends(get_database_connection), +): + """ + 根据 burst_incident 查询爆管定位结果 + """ + try: + return await SchemeRepository.get_burst_locate_result_by_incident( + conn, burst_incident + ) + except Exception as e: + raise HTTPException( + status_code=500, + detail=f"根据 burst_incident 查询爆管定位结果时发生错误: {str(e)}", + ) diff --git a/app/api/v1/endpoints/risk.py b/app/api/v1/endpoints/risk.py new file mode 100644 index 0000000..43addb9 --- /dev/null +++ b/app/api/v1/endpoints/risk.py @@ -0,0 +1,44 @@ +from typing import Any, List, Dict +from fastapi import APIRouter +from app.services.tjnetwork import ( + get_pipe_risk_probability_now, + get_pipe_risk_probability, + get_pipes_risk_probability, + get_network_pipe_risk_probability_now, + get_pipe_risk_probability_geometries, +) + +router = APIRouter() + +@router.get("/getpiperiskprobabilitynow/") +async def fastapi_get_pipe_risk_probability_now( + network: str, pipe_id: str +) -> dict[str, Any]: + return get_pipe_risk_probability_now(network, pipe_id) + + +@router.get("/getpiperiskprobability/") +async def fastapi_get_pipe_risk_probability( + network: str, pipe_id: str +) -> dict[str, Any]: + return get_pipe_risk_probability(network, pipe_id) + + +@router.get("/getpipesriskprobability/") +async def fastapi_get_pipes_risk_probability( + network: str, pipe_ids: str +) -> list[dict[str, Any]]: + pipeids = pipe_ids.split(",") + return get_pipes_risk_probability(network, pipeids) + + +@router.get("/getnetworkpiperiskprobabilitynow/") +async def fastapi_get_network_pipe_risk_probability_now( + network: str, +) -> list[dict[str, Any]]: + return get_network_pipe_risk_probability_now(network) + + +@router.get("/getpiperiskprobabilitygeometries/") +async def fastapi_get_pipe_risk_probability_geometries(network: str) -> dict[str, Any]: + return get_pipe_risk_probability_geometries(network) diff --git a/app/api/v1/endpoints/scada.py b/app/api/v1/endpoints/scada.py new file mode 100644 index 0000000..dc871a6 --- /dev/null +++ b/app/api/v1/endpoints/scada.py @@ -0,0 +1,169 @@ +from typing import Any +from fastapi import APIRouter, Request +from app.services.tjnetwork import ( + ChangeSet, + get_scada_info, + get_all_scada_info, + get_scada_device_schema, + get_scada_device, + set_scada_device, + add_scada_device, + delete_scada_device, + clean_scada_device, + get_all_scada_device_ids, + get_all_scada_devices, + get_scada_device_data_schema, + get_scada_device_data, + set_scada_device_data, + add_scada_device_data, + delete_scada_device_data, + clean_scada_device_data, + get_scada_element_schema, + get_scada_element, + set_scada_element, + add_scada_element, + delete_scada_element, + clean_scada_element, + get_all_scada_elements, + get_scada_element_schema, + get_scada_info_schema, +) + +router = APIRouter() + +@router.get("/getscadaproperties/") +async def fast_get_scada_properties(network: str, scada: str) -> dict[str, Any]: + return get_scada_info(network, scada) + +@router.get("/getallscadaproperties/") +async def fast_get_all_scada_properties(network: str) -> list[dict[str, Any]]: + return get_all_scada_info(network) + + +############################################################ +# scada_device 29 +############################################################ + +@router.get("/getscadadeviceschema/") +async def fastapi_get_scada_device_schema(network: str) -> dict[str, dict[str, Any]]: + return get_scada_device_schema(network) + +@router.get("/getscadadevice/") +async def fastapi_get_scada_device(network: str, id: str) -> dict[str, Any]: + return get_scada_device(network, id) + +@router.post("/setscadadevice/", response_model=None) +async def fastapi_set_scada_device(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_scada_device(network, ChangeSet(props)) + +@router.post("/addscadadevice/", response_model=None) +async def fastapi_add_scada_device(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_scada_device(network, ChangeSet(props)) + +@router.post("/deletescadadevice/", response_model=None) +async def fastapi_delete_scada_device(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_scada_device(network, ChangeSet(props)) + +@router.post("/cleanscadadevice/", response_model=None) +async def fastapi_clean_scada_device(network: str) -> ChangeSet: + return clean_scada_device(network) + +@router.get("/getallscadadeviceids/") +async def fastapi_get_all_scada_device_ids(network: str) -> list[str]: + return get_all_scada_device_ids(network) + +@router.get("/getallscadadevices/") +async def fastapi_get_all_scada_devices(network: str) -> list[dict[str, Any]]: + return get_all_scada_devices(network) + + +############################################################ +# scada_device_data 30 +############################################################ + +@router.get("/getscadadevicedataschema/") +async def fastapi_get_scada_device_data_schema( + network: str, +) -> dict[str, dict[str, Any]]: + return get_scada_device_data_schema(network) + +@router.get("/getscadadevicedata/") +async def fastapi_get_scada_device_data(network: str, device_id: str) -> dict[str, Any]: + return get_scada_device_data(network, device_id) + +@router.post("/setscadadevicedata/", response_model=None) +async def fastapi_set_scada_device_data(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_scada_device_data(network, ChangeSet(props)) + +@router.post("/addscadadevicedata/", response_model=None) +async def fastapi_add_scada_device_data(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_scada_device_data(network, ChangeSet(props)) + +@router.post("/deletescadadevicedata/", response_model=None) +async def fastapi_delete_scada_device_data(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_scada_device_data(network, ChangeSet(props)) + +@router.post("/cleanscadadevicedata/", response_model=None) +async def fastapi_clean_scada_device_data(network: str) -> ChangeSet: + return clean_scada_device_data(network) + + +############################################################ +# scada_element 31 +############################################################ + +@router.get("/getscadaelementschema/") +async def fastapi_get_scada_element_schema( + network: str, +) -> dict[str, dict[str, Any]]: + return get_scada_element_schema(network) + +@router.get("/getscadaelements/") +async def fastapi_get_scada_elements(network: str) -> list[dict[str, Any]]: + return get_all_scada_elements(network) + +@router.get("/getscadaelement/") +async def fastapi_get_scada_element(network: str, id: str) -> dict[str, Any]: + return get_scada_element(network, id) + +@router.post("/setscadaelement/", response_model=None) +async def fastapi_set_scada_element(network: str, req: Request) -> ChangeSet: + props = await req.json() + return set_scada_element(network, ChangeSet(props)) + +@router.post("/addscadaelement/", response_model=None) +async def fastapi_add_scada_element(network: str, req: Request) -> ChangeSet: + props = await req.json() + return add_scada_element(network, ChangeSet(props)) + +@router.post("/deletescadaelement/", response_model=None) +async def fastapi_delete_scada_element(network: str, req: Request) -> ChangeSet: + props = await req.json() + return delete_scada_element(network, ChangeSet(props)) + +@router.post("/cleanscadaelement/", response_model=None) +async def fastapi_clean_scada_element(network: str) -> ChangeSet: + return clean_scada_element(network) + + +############################################################ +# scada_info 38 +############################################################ + +@router.get("/getscadainfoschema/") +async def fastapi_get_scada_info_schema(network: str) -> dict[str, dict[str, Any]]: + return get_scada_info_schema(network) + +@router.get("/getscadainfo/") +async def fastapi_get_scada_info(network: str, id: str) -> dict[str, Any]: + return get_scada_info(network, id) + +@router.get("/getallscadainfo/") +async def fastapi_get_all_scada_info(network: str) -> list[dict[str, Any]]: + return get_all_scada_info(network) diff --git a/app/api/v1/endpoints/schemes.py b/app/api/v1/endpoints/schemes.py new file mode 100644 index 0000000..0e5cb02 --- /dev/null +++ b/app/api/v1/endpoints/schemes.py @@ -0,0 +1,17 @@ +from fastapi import APIRouter +from typing import Any, List, Dict +from app.services.tjnetwork import get_scheme_schema, get_scheme, get_all_schemes + +router = APIRouter() + +@router.get("/getschemeschema/") +async def fastapi_get_scheme_schema(network: str) -> dict[str, dict[Any, Any]]: + return get_scheme_schema(network) + +@router.get("/getscheme/") +async def fastapi_get_scheme(network: str, schema_name: str) -> dict[Any, Any]: + return get_scheme(network, schema_name) + +@router.get("/getallschemes/") +async def fastapi_get_all_schemes(network: str) -> list[dict[Any, Any]]: + return get_all_schemes(network) diff --git a/app/api/v1/endpoints/simulation.py b/app/api/v1/endpoints/simulation.py new file mode 100644 index 0000000..56dea9f --- /dev/null +++ b/app/api/v1/endpoints/simulation.py @@ -0,0 +1,670 @@ +from typing import Any, List, Optional +from datetime import datetime, timedelta +import json +import os +import shutil +import threading +import pandas as pd +from fastapi import APIRouter, HTTPException, File, UploadFile, Query +from fastapi.responses import PlainTextResponse +import app.infra.db.influxdb.api as influxdb_api +import app.services.simulation as simulation +import app.services.globals as globals +from app.infra.cache.redis_client import redis_client +from app.services.tjnetwork import ( + run_project, + run_project_return_dict, + run_inp, + dump_output, +) +from app.algorithms.simulation.scenarios import ( + burst_analysis, + valve_close_analysis, + flushing_analysis, + contaminant_simulation, + age_analysis, + # scheduling_analysis, + pressure_regulation, +) +from app.algorithms.sensor import ( + pressure_sensor_placement_sensitivity, + pressure_sensor_placement_kmeans, +) +import app.algorithms.cleaning.flow as flow_data_clean +import app.algorithms.cleaning.pressure as pressure_data_clean +from app.services.network_import import network_update +from app.services.simulation_ops import ( + project_management, + scheduling_simulation, + daily_scheduling_simulation, +) +from app.services.valve_isolation import analyze_valve_isolation +from pydantic import BaseModel + +router = APIRouter() + + +class RunSimulationManuallyByDate(BaseModel): + name: str + simulation_date: str + start_time: str + duration: int + + +class BurstAnalysis(BaseModel): + name: str + modify_pattern_start_time: str + burst_ID: List[str] | str | None = None + burst_size: List[float] | float | int | None = None + modify_total_duration: int = 900 + modify_fixed_pump_pattern: Optional[dict[str, list]] = None + modify_variable_pump_pattern: Optional[dict[str, list]] = None + modify_valve_opening: Optional[dict[str, float]] = None + scheme_name: Optional[str] = None + + +class SchedulingAnalysis(BaseModel): + network: str + start_time: str + pump_control: dict + tank_id: str + water_plant_output_id: str + time_delta: Optional[int] = 300 + + +class PressureRegulation(BaseModel): + network: str + start_time: str + pump_control: dict + tank_init_level: Optional[dict] = None + duration: Optional[int] = 900 + scheme_name: Optional[str] = None + + +class ProjectManagement(BaseModel): + network: str + start_time: str + pump_control: dict + tank_init_level: Optional[dict] = None + region_demand: Optional[dict] = None + + +class DailySchedulingAnalysis(BaseModel): + network: str + start_time: str + pump_control: dict + reservoir_id: str + tank_id: str + water_plant_output_id: str + time_delta: Optional[int] = 300 + + +class PumpFailureState(BaseModel): + time: str + pump_status: dict + + +class PressureSensorPlacement(BaseModel): + name: str + scheme_name: str + sensor_number: int + min_diameter: int = 0 + username: str + + +def run_simulation_manually_by_date( + network_name: str, base_date: datetime, start_time: str, duration: int +) -> None: + time_parts = list(map(int, start_time.split(":"))) + if len(time_parts) == 2: + start_hour, start_minute = time_parts + start_second = 0 + elif len(time_parts) == 3: + start_hour, start_minute, start_second = time_parts + else: + raise ValueError("Invalid start_time format. Use HH:MM or HH:MM:SS") + + start_datetime = base_date.replace( + hour=start_hour, minute=start_minute, second=start_second + ) + end_datetime = start_datetime + timedelta(minutes=duration) + current_time = start_datetime + while current_time < end_datetime: + iso_time = current_time.strftime("%Y-%m-%dT%H:%M:%S") + "+08:00" + simulation.run_simulation( + name=network_name, + simulation_type="realtime", + modify_pattern_start_time=iso_time, + ) + current_time += timedelta(minutes=15) + + +# 必须用这个PlainTextResponse,不然每个key都有引号 +@router.get("/runproject/", response_class=PlainTextResponse) +async def run_project_endpoint(network: str) -> str: + lock_key = "exclusive_api_lock" + timeout = 120 # 锁自动过期时间(秒) + + # 尝试获取锁(NX=True: 不存在时设置,EX=timeout: 过期时间) + acquired = redis_client.set(lock_key, "locked", nx=True, ex=timeout) + + if not acquired: + raise HTTPException(status_code=409, detail="is in simulation") + else: + try: + return run_project(network) + finally: + # 手动释放锁(可选,依赖过期时间自动释放更安全) + redis_client.delete(lock_key) + + +# DingZQ, 2025-02-04, 返回dict[str, Any] +# output 和 report +# output 是 json +# report 是 text +@router.get("/runprojectreturndict/") +async def run_project_return_dict_endpoint(network: str) -> dict[str, Any]: + lock_key = "exclusive_api_lock" + timeout = 120 # 锁自动过期时间(秒) + + # 尝试获取锁(NX=True: 不存在时设置,EX=timeout: 过期时间) + acquired = redis_client.set(lock_key, "locked", nx=True, ex=timeout) + + if not acquired: + raise HTTPException(status_code=409, detail="is in simulation") + else: + try: + return run_project_return_dict(network) + finally: + # 手动释放锁(可选,依赖过期时间自动释放更安全) + redis_client.delete(lock_key) + + +# put in inp folder, name without extension +@router.get("/runinp/") +async def run_inp_endpoint(network: str) -> str: + return run_inp(network) + + +# path is absolute path +@router.get("/dumpoutput/") +async def dump_output_endpoint(output: str) -> str: + return dump_output(output) + + +# Analysis Endpoints +@router.get("/burstanalysis/") +async def burst_analysis_endpoint( + network: str, pipe_id: str, start_time: str, end_time: str, burst_flow: float +): + return burst_analysis(network, pipe_id, start_time, end_time, burst_flow) + + +@router.get("/burst_analysis/") +async def fastapi_burst_analysis( + network: str = Query(...), + modify_pattern_start_time: str = Query(...), + burst_ID: list[str] = Query(...), + burst_size: list[float] = Query(...), + modify_total_duration: int = Query(...), + scheme_name: str = Query(...), +) -> str: + burst_analysis( + name=network, + modify_pattern_start_time=modify_pattern_start_time, + burst_ID=burst_ID, + burst_size=burst_size, + modify_total_duration=modify_total_duration, + scheme_name=scheme_name, + ) + return "success" + + +@router.get("/valvecloseanalysis/") +async def valve_close_analysis_endpoint( + network: str, valve_id: str, start_time: str, end_time: str +): + return valve_close_analysis(network, valve_id, start_time, end_time) + + +@router.get("/valve_close_analysis/", response_class=PlainTextResponse) +async def fastapi_valve_close_analysis( + network: str, + start_time: str, + valves: List[str] = Query(...), + duration: int | None = None, +) -> str: + result = valve_close_analysis( + name=network, + modify_pattern_start_time=start_time, + modify_total_duration=duration or 900, + modify_valve_opening={valve_id: 0.0 for valve_id in valves}, + ) + return result or "success" + + +@router.get("/valve_isolation_analysis/") +async def valve_isolation_endpoint( + network: str, + accident_element: List[str] = Query(...), + disabled_valves: List[str] = Query(None), +): + result = { + "accident_element": "P461309", + "accident_elements": ["P461309"], + "affected_nodes": [ + "J316629_A", + "J317037_B", + "J317060_B", + "J408189_B", + "J499996", + "J524940", + "J535933", + "J58841", + ], + "isolatable": True, + "must_close_valves": ["210521658", "V12974", "V12986", "V12993"], + "optional_valves": [], + } + result = analyze_valve_isolation(network, accident_element, disabled_valves) + return result + + +@router.get("/flushinganalysis/") +async def flushing_analysis_endpoint( + network: str, pipe_id: str, start_time: str, duration: float, flow: float +): + return flushing_analysis(network, pipe_id, start_time, duration, flow) + + +@router.get("/flushing_analysis/", response_class=PlainTextResponse) +async def fastapi_flushing_analysis( + network: str, + start_time: str, + valves: List[str] = Query(...), + valves_k: List[float] = Query(...), + drainage_node_ID: str = Query(...), + flush_flow: float = 0, + duration: int | None = None, + scheme_name: str | None = None, +) -> str: + valve_opening = { + valve_id: float(valves_k[idx]) for idx, valve_id in enumerate(valves) + } + result = flushing_analysis( + name=network, + modify_pattern_start_time=start_time, + modify_total_duration=duration or 900, + modify_valve_opening=valve_opening, + drainage_node_ID=drainage_node_ID, + flushing_flow=flush_flow, + scheme_name=scheme_name, + ) + return result or "success" + + +@router.get("/contaminant_simulation/", response_class=PlainTextResponse) +async def fastapi_contaminant_simulation( + network: str, + start_time: str, + source: str, + concentration: float, + duration: int, + scheme_name: str | None = None, + pattern: str | None = None, +) -> str: + result = contaminant_simulation( + name=network, + modify_pattern_start_time=start_time, + scheme_name=scheme_name, + modify_total_duration=duration, + source=source, + concentration=concentration, + source_pattern=pattern, + ) + return result or "success" + + +@router.get("/ageanalysis/") +async def age_analysis_endpoint(network: str): + return age_analysis(network) + + +@router.get("/age_analysis/", response_class=PlainTextResponse) +async def fastapi_age_analysis( + network: str, start_time: str, end_time: str, duration: int +) -> str: + result = age_analysis(network, start_time, duration) + return result or "success" + + +# @router.get("/schedulinganalysis/") +# async def scheduling_analysis_endpoint(network: str): +# return scheduling_analysis(network) + + +@router.get("/pressureregulation/") +async def pressure_regulation_endpoint( + network: str, target_node: str, target_pressure: float +): + return pressure_regulation(network, target_node, target_pressure) + + +@router.post("/pressure_regulation/") +async def fastapi_pressure_regulation(data: PressureRegulation) -> str: + item = data.dict() + simulation.query_corresponding_element_id_and_query_id(item["network"]) + fixed_pumps = set(globals.fixed_pumps_id.keys()) + variable_pumps = set(globals.variable_pumps_id.keys()) + fixed_pump_pattern: dict[str, list] = {} + variable_pump_pattern: dict[str, list] = {} + for pump_id, values in item["pump_control"].items(): + if pump_id in variable_pumps: + variable_pump_pattern[pump_id] = values + else: + fixed_pump_pattern[pump_id] = values + pressure_regulation( + name=item["network"], + modify_pattern_start_time=item["start_time"], + modify_total_duration=item["duration"] or 900, + modify_tank_initial_level=item["tank_init_level"], + modify_fixed_pump_pattern=fixed_pump_pattern or None, + modify_variable_pump_pattern=variable_pump_pattern or None, + scheme_name=item["scheme_name"], + ) + return "success" + + +@router.get("/projectmanagement/") +async def project_management_endpoint(network: str): + return project_management(network) + + +@router.post("/project_management/") +async def fastapi_project_management(data: ProjectManagement) -> str: + item = data.dict() + return project_management( + prj_name=item["network"], + start_datetime=item["start_time"], + pump_control=item["pump_control"], + tank_initial_level_control=item["tank_init_level"], + region_demand_control=item["region_demand"], + ) + + +# @router.get("/dailyschedulinganalysis/") +# async def daily_scheduling_analysis_endpoint(network: str): +# return daily_scheduling_analysis(network) + + +@router.post("/scheduling_analysis/") +async def fastapi_scheduling_analysis(data: SchedulingAnalysis) -> str: + item = data.dict() + return scheduling_simulation( + item["network"], + item["start_time"], + item["pump_control"], + item["tank_id"], + item["water_plant_output_id"], + item["time_delta"], + ) + + +@router.post("/daily_scheduling_analysis/") +async def fastapi_daily_scheduling_analysis(data: DailySchedulingAnalysis) -> str: + item = data.dict() + return daily_scheduling_simulation( + item["network"], + item["start_time"], + item["pump_control"], + item["reservoir_id"], + item["tank_id"], + item["water_plant_output_id"], + ) + + +@router.post("/network_project/") +async def fastapi_network_project(file: UploadFile = File()) -> str: + temp_file_dir = "./inp/" + if not os.path.exists(temp_file_dir): + os.mkdir(temp_file_dir) + temp_file_name = f'network_project_{datetime.now().strftime("%Y%m%d")}' + temp_file_path = f"{temp_file_dir}{temp_file_name}.inp" + with open(temp_file_path, "wb") as buffer: + shutil.copyfileobj(file.file, buffer) + return run_inp(temp_file_name) + + +@router.get("/networkupdate/") +async def network_update_endpoint(network: str): + return network_update(network) + + +@router.post("/network_update/") +async def fastapi_network_update(file: UploadFile = File()) -> str: + default_folder = "./" + temp_file_name = f'network_update_{datetime.now().strftime("%Y%m%d")}' + temp_file_path = os.path.join(default_folder, temp_file_name) + try: + with open(temp_file_path, "wb") as buffer: + shutil.copyfileobj(file.file, buffer) + network_update(temp_file_path) + return json.dumps({"message": "管网更新成功"}) + except Exception as exc: + raise HTTPException(status_code=500, detail=f"数据库操作失败: {exc}") + + +# @router.get("/pumpfailure/") +# async def pump_failure_endpoint(network: str, pump_id: str, time: str): +# return pump_failure(network, pump_id, time) + + +@router.post("/pump_failure/") +async def fastapi_pump_failure(data: PumpFailureState) -> str: + item = data.dict() + with open("./pump_failure_message.txt", "a", encoding="utf-8-sig") as f1: + f1.write("[{}] {}\n".format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"), item)) + with open("./pump_failure_status.txt", "r", encoding="utf-8-sig") as f2: + lines = f2.readlines() + first_stage_pump_status_dict = json.loads(json.dumps(eval(lines[0]))) + second_stage_pump_status_dict = json.loads(json.dumps(eval(lines[-1]))) + pump_status_dict = { + "first": first_stage_pump_status_dict, + "second": second_stage_pump_status_dict, + } + status_info = item.copy() + for pump_type in status_info["pump_status"].keys(): + if pump_type in pump_status_dict.keys(): + if all( + pump_id in pump_status_dict[pump_type].keys() + for pump_id in status_info["pump_status"][pump_type].keys() + ): + for pump_id in status_info["pump_status"][pump_type].keys(): + pump_status_dict[pump_type][pump_id] = int( + status_info["pump_status"][pump_type][pump_id] + ) + else: + return json.dumps("ERROR: Wrong Pump ID") + else: + return json.dumps("ERROR: Wrong Pump Type") + with open("./pump_failure_status.txt", "w", encoding="utf-8-sig") as f2_: + f2_.write( + "{}\n{}".format(pump_status_dict["first"], pump_status_dict["second"]) + ) + return json.dumps("SUCCESS") + + +@router.get("/pressuresensorplacementsensitivity/") +async def pressure_sensor_placement_sensitivity_endpoint( + name: str, scheme_name: str, sensor_number: int, min_diameter: int, username: str +): + return pressure_sensor_placement_sensitivity( + name, scheme_name, sensor_number, min_diameter, username + ) + + +@router.post("/pressure_sensor_placement_sensitivity/") +async def fastapi_pressure_sensor_placement_sensitivity( + data: PressureSensorPlacement, +) -> None: + item = data.dict() + pressure_sensor_placement_sensitivity( + name=item["name"], + scheme_name=item["scheme_name"], + sensor_number=item["sensor_number"], + min_diameter=item["min_diameter"], + username=item["username"], + ) + + +@router.get("/pressuresensorplacementkmeans/") +async def pressure_sensor_placement_kmeans_endpoint( + name: str, scheme_name: str, sensor_number: int, min_diameter: int, username: str +): + return pressure_sensor_placement_kmeans( + name, scheme_name, sensor_number, min_diameter, username + ) + + +@router.post("/pressure_sensor_placement_kmeans/") +async def fastapi_pressure_sensor_placement_kmeans( + data: PressureSensorPlacement, +) -> None: + item = data.dict() + pressure_sensor_placement_kmeans( + name=item["name"], + scheme_name=item["scheme_name"], + sensor_number=item["sensor_number"], + min_diameter=item["min_diameter"], + username=item["username"], + ) + + +@router.post("/sensorplacementscheme/create") +async def fastapi_pressure_sensor_placement( + network: str = Query(...), + scheme_name: str = Query(...), + sensor_type: str = Query(...), + method: str = Query(...), + sensor_count: int = Query(...), + min_diameter: int = Query(0), + user_name: str = Query(...), +) -> str: + if method not in ["sensitivity", "kmeans"]: + raise HTTPException( + status_code=400, detail="Invalid method. Must be 'sensitivity' or 'kmeans'" + ) + if method == "sensitivity": + pressure_sensor_placement_sensitivity( + name=network, + scheme_name=scheme_name, + sensor_number=sensor_count, + min_diameter=min_diameter, + username=user_name, + ) + elif method == "kmeans": + pressure_sensor_placement_kmeans( + name=network, + scheme_name=scheme_name, + sensor_number=sensor_count, + min_diameter=min_diameter, + username=user_name, + ) + return "success" + + +@router.post("/scadadevicedatacleaning/") +async def fastapi_scada_device_data_cleaning( + network: str = Query(...), + ids_list: List[str] = Query(...), + start_time: str = Query(...), + end_time: str = Query(...), + user_name: str = Query(...), +) -> str: + item = { + "network": network, + "ids": ids_list, + "start_time": start_time, + "end_time": end_time, + "user_name": user_name, + } + query_ids_list = item["ids"][0].split(",") + scada_data = influxdb_api.query_SCADA_data_by_device_ID_and_timerange( + query_ids_list=query_ids_list, + start_time=item["start_time"], + end_time=item["end_time"], + ) + scada_device_info = influxdb_api.query_pg_scada_info(item["network"]) + scada_device_info_dict = {info["id"]: info for info in scada_device_info} + type_groups: dict[str, list[str]] = {} + for device_id in query_ids_list: + device_info = scada_device_info_dict.get(device_id, {}) + device_type = device_info.get("type", "unknown") + type_groups.setdefault(device_type, []).append(device_id) + for device_type, device_ids in type_groups.items(): + if device_type not in ["pressure", "pipe_flow"]: + continue + type_scada_data = { + device_id: scada_data[device_id] + for device_id in device_ids + if device_id in scada_data + } + if not type_scada_data: + continue + time_list = [record["time"] for record in next(iter(type_scada_data.values()))] + df = pd.DataFrame({"time": time_list}) + for device_id in device_ids: + if device_id in type_scada_data: + values = [record["value"] for record in type_scada_data[device_id]] + df[device_id] = values + if device_type == "pressure": + cleaned_value_df = pressure_data_clean.clean_pressure_data_df_km(df) + elif device_type == "pipe_flow": + cleaned_value_df = flow_data_clean.clean_flow_data_df_kf(df) + cleaned_value_df = pd.DataFrame(cleaned_value_df) + cleaned_df = pd.concat([df["time"], cleaned_value_df], axis=1) + influxdb_api.import_multicolumn_data_from_dict( + data_dict=cleaned_df.to_dict("list"), + raw=False, + ) + return "success" + + +@router.post("/runsimulationmanuallybydate/") +async def fastapi_run_simulation_manually_by_date( + data: RunSimulationManuallyByDate, +) -> dict[str, str]: + item = data.dict() + try: + simulation.query_corresponding_element_id_and_query_id(item["name"]) + simulation.query_corresponding_pattern_id_and_query_id(item["name"]) + region_result = simulation.query_non_realtime_region(item["name"]) + globals.source_outflow_region_id = simulation.get_source_outflow_region_id( + item["name"], region_result + ) + globals.realtime_region_pipe_flow_and_demand_id = ( + simulation.query_realtime_region_pipe_flow_and_demand_id( + item["name"], region_result + ) + ) + globals.pipe_flow_region_patterns = simulation.query_pipe_flow_region_patterns( + item["name"] + ) + globals.non_realtime_region_patterns = ( + simulation.query_non_realtime_region_patterns(item["name"], region_result) + ) + ( + globals.source_outflow_region_patterns, + globals.realtime_region_pipe_flow_and_demand_patterns, + ) = simulation.get_realtime_region_patterns( + item["name"], + globals.source_outflow_region_id, + globals.realtime_region_pipe_flow_and_demand_id, + ) + base_date = datetime.strptime(item["simulation_date"], "%Y-%m-%d") + run_simulation_manually_by_date( + item["name"], base_date, item["start_time"], item["duration"] + ) + return {"status": "success"} + except Exception as exc: + return {"status": "error", "message": str(exc)} diff --git a/app/api/v1/endpoints/snapshots.py b/app/api/v1/endpoints/snapshots.py new file mode 100644 index 0000000..d8e8dd9 --- /dev/null +++ b/app/api/v1/endpoints/snapshots.py @@ -0,0 +1,111 @@ +from fastapi import APIRouter, Request +from app.services.tjnetwork import ( + ChangeSet, + get_current_operation, + execute_undo, + execute_redo, + list_snapshot, + have_snapshot, + have_snapshot_for_operation, + have_snapshot_for_current_operation, + take_snapshot_for_operation, + take_snapshot_for_current_operation, + take_snapshot, + pick_snapshot, + pick_operation, + sync_with_server, + execute_batch_commands, + execute_batch_command, + get_restore_operation, + set_restore_operation, +) + +router = APIRouter() + +@router.get("/getcurrentoperationid/") +async def get_current_operation_id_endpoint(network: str) -> int: + return get_current_operation(network) + +@router.post("/undo/") +async def undo_endpoint(network: str): + return execute_undo(network) + +@router.post("/redo/") +async def redo_endpoint(network: str): + return execute_redo(network) + +@router.get("/getsnapshots/") +async def list_snapshot_endpoint(network: str) -> list[tuple[int, str]]: + return list_snapshot(network) + +@router.get("/havesnapshot/") +async def have_snapshot_endpoint(network: str, tag: str) -> bool: + return have_snapshot(network, tag) + +@router.get("/havesnapshotforoperation/") +async def have_snapshot_for_operation_endpoint(network: str, operation: int) -> bool: + return have_snapshot_for_operation(network, operation) + +@router.get("/havesnapshotforcurrentoperation/") +async def have_snapshot_for_current_operation_endpoint(network: str) -> bool: + return have_snapshot_for_current_operation(network) + +@router.post("/takesnapshotforoperation/") +async def take_snapshot_for_operation_endpoint( + network: str, operation: int, tag: str +) -> None: + return take_snapshot_for_operation(network, operation, tag) + +@router.post("/takesnapshotforcurrentoperation") +async def take_snapshot_for_current_operation_endpoint(network: str, tag: str) -> None: + return take_snapshot_for_current_operation(network, tag) + +# 兼容旧拼写: takenapshotforcurrentoperation +@router.post("/takenapshotforcurrentoperation") +async def take_snapshot_for_current_operation_legacy_endpoint( + network: str, tag: str +) -> None: + return take_snapshot_for_current_operation(network, tag) + +@router.post("/takesnapshot/") +async def take_snapshot_endpoint(network: str, tag: str) -> None: + return take_snapshot(network, tag) + +@router.post("/picksnapshot/", response_model=None) +async def pick_snapshot_endpoint(network: str, tag: str, discard: bool = False) -> ChangeSet: + return pick_snapshot(network, tag, discard) + +@router.post("/pickoperation/", response_model=None) +async def pick_operation_endpoint( + network: str, operation: int, discard: bool = False +) -> ChangeSet: + return pick_operation(network, operation, discard) + +@router.get("/syncwithserver/", response_model=None) +async def sync_with_server_endpoint(network: str, operation: int) -> ChangeSet: + return sync_with_server(network, operation) + +@router.post("/batch/", response_model=None) +async def execute_batch_commands_endpoint(network: str, req: Request) -> ChangeSet: + jo_root = await req.json() + cs: ChangeSet = ChangeSet() + cs.operations = jo_root["operations"] + rcs = execute_batch_commands(network, cs) + return rcs + +@router.post("/compressedbatch/", response_model=None) +async def execute_compressed_batch_commands_endpoint( + network: str, req: Request +) -> ChangeSet: + jo_root = await req.json() + cs: ChangeSet = ChangeSet() + cs.operations = jo_root["operations"] + return execute_batch_command(network, cs) + +@router.get("/getrestoreoperation/") +async def get_restore_operation_endpoint(network: str) -> int: + return get_restore_operation(network) + +@router.post("/setrestoreoperation/") +async def set_restore_operation_endpoint(network: str, operation: int) -> None: + return set_restore_operation(network, operation) diff --git a/app/api/v1/endpoints/timeseries/__init__.py b/app/api/v1/endpoints/timeseries/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/api/v1/endpoints/timeseries/composite.py b/app/api/v1/endpoints/timeseries/composite.py new file mode 100644 index 0000000..116532b --- /dev/null +++ b/app/api/v1/endpoints/timeseries/composite.py @@ -0,0 +1,205 @@ +from fastapi import APIRouter, Depends, HTTPException, Query +from datetime import datetime +from psycopg import AsyncConnection + +from app.infra.db.timescaledb.composite_queries import CompositeQueries +from .dependencies import get_timescale_connection, get_postgres_connection + +router = APIRouter() + + +@router.get("/composite/scada-simulation") +async def get_scada_associated_simulation_data( + start_time: datetime, + end_time: datetime, + device_ids: str, + scheme_type: str = Query(None, description="指定方案名称,若为空则查询实时数据"), + scheme_name: str = Query(None, description="指定方案名称,若为空则查询实时数据"), + timescale_conn: AsyncConnection = Depends(get_timescale_connection), + postgres_conn: AsyncConnection = Depends(get_postgres_connection), +): + """ + 获取 SCADA 关联的 link/node 模拟值 + + 根据传入的 SCADA device_ids,找到关联的 link/node, + 并根据对应的 type,查询对应的模拟数据 + """ + try: + device_ids_list = ( + [id.strip() for id in device_ids.split(",") if id.strip()] + if device_ids + else [] + ) + + if scheme_type and scheme_name: + result = await CompositeQueries.get_scada_associated_scheme_simulation_data( + timescale_conn, + postgres_conn, + device_ids_list, + start_time, + end_time, + scheme_type, + scheme_name, + ) + else: + result = ( + await CompositeQueries.get_scada_associated_realtime_simulation_data( + timescale_conn, + postgres_conn, + device_ids_list, + start_time, + end_time, + ) + ) + if result is None: + raise HTTPException(status_code=404, detail="No simulation data found") + return result + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.get("/composite/element-simulation") +async def get_feature_simulation_data( + start_time: datetime, + end_time: datetime, + feature_infos: str = Query( + ..., description="特征信息,格式: id1:type1,id2:type2,type为pipe或junction" + ), + scheme_type: str = Query(None, description="指定方案类型,若为空则查询实时数据"), + scheme_name: str = Query(None, description="指定方案名称,若为空则查询实时数据"), + timescale_conn: AsyncConnection = Depends(get_timescale_connection), +): + """ + 获取 link/node 模拟值 + + 根据传入的 featureInfos,找到关联的 link/node, + 并根据对应的 type,查询对应的模拟数据 + + Args: + feature_infos: 格式为 "element_id1:type1,element_id2:type2" + 例如: "P1:pipe,J1:junction" + """ + try: + feature_infos_list = [] + if feature_infos: + for item in feature_infos.split(","): + item = item.strip() + if ":" in item: + element_id, element_type = item.split(":", 1) + feature_infos_list.append( + (element_id.strip(), element_type.strip()) + ) + + if not feature_infos_list: + raise HTTPException(status_code=400, detail="feature_infos cannot be empty") + + if scheme_type and scheme_name: + result = await CompositeQueries.get_scheme_simulation_data( + timescale_conn, + feature_infos_list, + start_time, + end_time, + scheme_type, + scheme_name, + ) + else: + result = await CompositeQueries.get_realtime_simulation_data( + timescale_conn, + feature_infos_list, + start_time, + end_time, + ) + + if result is None: + raise HTTPException(status_code=404, detail="No simulation data found") + return result + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.get("/composite/element-scada") +async def get_element_associated_scada_data( + element_id: str, + start_time: datetime, + end_time: datetime, + use_cleaned: bool = Query(False, description="是否使用清洗后的数据"), + timescale_conn: AsyncConnection = Depends(get_timescale_connection), + postgres_conn: AsyncConnection = Depends(get_postgres_connection), +): + """ + 获取 link/node 关联的 SCADA 监测值 + + 根据传入的 link/node id,匹配 SCADA 信息, + 如果存在关联的 SCADA device_id,获取实际的监测数据 + """ + try: + result = await CompositeQueries.get_element_associated_scada_data( + timescale_conn, postgres_conn, element_id, start_time, end_time, use_cleaned + ) + if result is None: + raise HTTPException( + status_code=404, detail="No associated SCADA data found" + ) + return result + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.post("/composite/clean-scada") +async def clean_scada_data( + device_ids: str, + start_time: datetime = Query(...), + end_time: datetime = Query(...), + timescale_conn: AsyncConnection = Depends(get_timescale_connection), + postgres_conn: AsyncConnection = Depends(get_postgres_connection), +): + """ + 清洗 SCADA 数据 + + 根据 device_ids 查询 monitored_value,清洗后更新 cleaned_value + """ + try: + if device_ids == "all": + device_ids_list = [] + else: + device_ids_list = ( + [id.strip() for id in device_ids.split(",") if id.strip()] + if device_ids + else [] + ) + return await CompositeQueries.clean_scada_data( + timescale_conn, postgres_conn, device_ids_list, start_time, end_time + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.get("/composite/pipeline-health-prediction") +async def predict_pipeline_health( + query_time: datetime = Query(..., description="查询时间"), + network_name: str = Query(..., description="管网数据库名称"), + timescale_conn: AsyncConnection = Depends(get_timescale_connection), +): + """ + 预测管道健康状况 + + 根据管网名称和当前时间,查询管道信息和实时数据, + 使用随机生存森林模型预测管道的生存概率 + + Args: + query_time: 查询时间 + db_name: 管网数据库名称 + + Returns: + 预测结果列表,每个元素包含 link_id 和对应的生存函数 + """ + try: + return await CompositeQueries.predict_pipeline_health( + timescale_conn, network_name, query_time + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + except FileNotFoundError as e: + raise HTTPException(status_code=404, detail=str(e)) + except Exception as e: + raise HTTPException(status_code=500, detail=f"内部服务器错误: {str(e)}") diff --git a/app/api/v1/endpoints/timeseries/dependencies.py b/app/api/v1/endpoints/timeseries/dependencies.py new file mode 100644 index 0000000..4e84a14 --- /dev/null +++ b/app/api/v1/endpoints/timeseries/dependencies.py @@ -0,0 +1,19 @@ +from fastapi import Depends +from psycopg import AsyncConnection + +from app.auth.project_dependencies import ( + get_project_pg_connection, + get_project_timescale_connection, +) + + +async def get_timescale_connection( + conn: AsyncConnection = Depends(get_project_timescale_connection), +): + yield conn + + +async def get_postgres_connection( + conn: AsyncConnection = Depends(get_project_pg_connection), +): + yield conn diff --git a/app/api/v1/endpoints/timeseries/realtime.py b/app/api/v1/endpoints/timeseries/realtime.py new file mode 100644 index 0000000..6f12c44 --- /dev/null +++ b/app/api/v1/endpoints/timeseries/realtime.py @@ -0,0 +1,126 @@ +from fastapi import APIRouter, Depends, HTTPException +from typing import List +from datetime import datetime +from psycopg import AsyncConnection + +from app.infra.db.timescaledb.repositories.realtime import RealtimeRepository +from .dependencies import get_timescale_connection + +router = APIRouter() + + +@router.post("/realtime/links/batch", status_code=201) +async def insert_realtime_links( + data: List[dict], conn: AsyncConnection = Depends(get_timescale_connection) +): + await RealtimeRepository.insert_links_batch(conn, data) + return {"message": f"Inserted {len(data)} records"} + + +@router.get("/realtime/links") +async def get_realtime_links( + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + return await RealtimeRepository.get_links_by_time_range(conn, start_time, end_time) + + +@router.delete("/realtime/links") +async def delete_realtime_links( + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + await RealtimeRepository.delete_links_by_time_range(conn, start_time, end_time) + return {"message": "Deleted successfully"} + + +@router.patch("/realtime/links/{link_id}/field") +async def update_realtime_link_field( + link_id: str, + time: datetime, + field: str, + value: float, + conn: AsyncConnection = Depends(get_timescale_connection), +): + try: + await RealtimeRepository.update_link_field(conn, time, link_id, field, value) + return {"message": "Updated successfully"} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.post("/realtime/nodes/batch", status_code=201) +async def insert_realtime_nodes( + data: List[dict], conn: AsyncConnection = Depends(get_timescale_connection) +): + await RealtimeRepository.insert_nodes_batch(conn, data) + return {"message": f"Inserted {len(data)} records"} + + +@router.get("/realtime/nodes") +async def get_realtime_nodes( + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + return await RealtimeRepository.get_nodes_by_time_range(conn, start_time, end_time) + + +@router.delete("/realtime/nodes") +async def delete_realtime_nodes( + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + await RealtimeRepository.delete_nodes_by_time_range(conn, start_time, end_time) + return {"message": "Deleted successfully"} + + +@router.post("/realtime/simulation/store", status_code=201) +async def store_realtime_simulation_result( + node_result_list: List[dict], + link_result_list: List[dict], + result_start_time: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + """Store realtime simulation results to TimescaleDB""" + await RealtimeRepository.store_realtime_simulation_result( + conn, node_result_list, link_result_list, result_start_time + ) + return {"message": "Simulation results stored successfully"} + + +@router.get("/realtime/query/by-time-property") +async def query_realtime_records_by_time_property( + query_time: str, + type: str, + property: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + """Query all realtime records by time and property""" + try: + results = await RealtimeRepository.query_all_record_by_time_property( + conn, query_time, type, property + ) + return {"results": results} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.get("/realtime/query/by-id-time") +async def query_realtime_simulation_by_id_time( + id: str, + type: str, + query_time: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + """Query realtime simulation results by id and time""" + try: + results = await RealtimeRepository.query_simulation_result_by_id_time( + conn, id, type, query_time + ) + return {"result": results} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) diff --git a/app/api/v1/endpoints/timeseries/scada.py b/app/api/v1/endpoints/timeseries/scada.py new file mode 100644 index 0000000..e36759f --- /dev/null +++ b/app/api/v1/endpoints/timeseries/scada.py @@ -0,0 +1,81 @@ +from fastapi import APIRouter, Depends, HTTPException +from typing import List +from datetime import datetime +from psycopg import AsyncConnection + +from app.infra.db.timescaledb.repositories.scada import ScadaRepository +from .dependencies import get_timescale_connection + +router = APIRouter() + + +@router.post("/scada/batch", status_code=201) +async def insert_scada_data( + data: List[dict], conn: AsyncConnection = Depends(get_timescale_connection) +): + await ScadaRepository.insert_scada_batch(conn, data) + return {"message": f"Inserted {len(data)} records"} + + +@router.get("/scada/by-ids-time-range") +async def get_scada_by_ids_time_range( + start_time: datetime, + end_time: datetime, + device_ids: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + device_ids_list = ( + [id.strip() for id in device_ids.split(",") if id.strip()] if device_ids else [] + ) + return await ScadaRepository.get_scada_by_ids_time_range( + conn, device_ids_list, start_time, end_time + ) + + +@router.get("/scada/by-ids-field-time-range") +async def get_scada_field_by_ids_time_range( + start_time: datetime, + end_time: datetime, + field: str, + device_ids: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + try: + device_ids_list = ( + [id.strip() for id in device_ids.split(",") if id.strip()] + if device_ids + else [] + ) + return await ScadaRepository.get_scada_field_by_id_time_range( + conn, device_ids_list, start_time, end_time, field + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.patch("/scada/{device_id}/field") +async def update_scada_field( + device_id: str, + time: datetime, + field: str, + value: float, + conn: AsyncConnection = Depends(get_timescale_connection), +): + try: + await ScadaRepository.update_scada_field(conn, time, device_id, field, value) + return {"message": "Updated successfully"} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.delete("/scada/by-id-time-range") +async def delete_scada_data( + device_id: str, + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + await ScadaRepository.delete_scada_by_id_time_range( + conn, device_id, start_time, end_time + ) + return {"message": "Deleted successfully"} diff --git a/app/api/v1/endpoints/timeseries/scheme.py b/app/api/v1/endpoints/timeseries/scheme.py new file mode 100644 index 0000000..307f7f1 --- /dev/null +++ b/app/api/v1/endpoints/timeseries/scheme.py @@ -0,0 +1,199 @@ +from fastapi import APIRouter, Depends, HTTPException +from typing import List +from datetime import datetime +from psycopg import AsyncConnection + +from app.infra.db.timescaledb.repositories.scheme import SchemeRepository +from .dependencies import get_timescale_connection + +router = APIRouter() + + +@router.post("/scheme/links/batch", status_code=201) +async def insert_scheme_links( + data: List[dict], conn: AsyncConnection = Depends(get_timescale_connection) +): + await SchemeRepository.insert_links_batch(conn, data) + return {"message": f"Inserted {len(data)} records"} + + +@router.get("/scheme/links") +async def get_scheme_links( + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + return await SchemeRepository.get_links_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time + ) + + +@router.get("/scheme/links/{link_id}/field") +async def get_scheme_link_field( + scheme_type: str, + scheme_name: str, + link_id: str, + start_time: datetime, + end_time: datetime, + field: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + try: + return await SchemeRepository.get_link_field_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time, link_id, field + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.patch("/scheme/links/{link_id}/field") +async def update_scheme_link_field( + scheme_type: str, + scheme_name: str, + link_id: str, + time: datetime, + field: str, + value: float, + conn: AsyncConnection = Depends(get_timescale_connection), +): + try: + await SchemeRepository.update_link_field( + conn, time, scheme_type, scheme_name, link_id, field, value + ) + return {"message": "Updated successfully"} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.delete("/scheme/links") +async def delete_scheme_links( + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + await SchemeRepository.delete_links_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time + ) + return {"message": "Deleted successfully"} + + +@router.post("/scheme/nodes/batch", status_code=201) +async def insert_scheme_nodes( + data: List[dict], conn: AsyncConnection = Depends(get_timescale_connection) +): + await SchemeRepository.insert_nodes_batch(conn, data) + return {"message": f"Inserted {len(data)} records"} + + +@router.get("/scheme/nodes/{node_id}/field") +async def get_scheme_node_field( + scheme_type: str, + scheme_name: str, + node_id: str, + start_time: datetime, + end_time: datetime, + field: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + try: + return await SchemeRepository.get_node_field_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time, node_id, field + ) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.patch("/scheme/nodes/{node_id}/field") +async def update_scheme_node_field( + scheme_type: str, + scheme_name: str, + node_id: str, + time: datetime, + field: str, + value: float, + conn: AsyncConnection = Depends(get_timescale_connection), +): + try: + await SchemeRepository.update_node_field( + conn, time, scheme_type, scheme_name, node_id, field, value + ) + return {"message": "Updated successfully"} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.delete("/scheme/nodes") +async def delete_scheme_nodes( + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + conn: AsyncConnection = Depends(get_timescale_connection), +): + await SchemeRepository.delete_nodes_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time + ) + return {"message": "Deleted successfully"} + + +@router.post("/scheme/simulation/store", status_code=201) +async def store_scheme_simulation_result( + scheme_type: str, + scheme_name: str, + node_result_list: List[dict], + link_result_list: List[dict], + result_start_time: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + """Store scheme simulation results to TimescaleDB""" + await SchemeRepository.store_scheme_simulation_result( + conn, + scheme_type, + scheme_name, + node_result_list, + link_result_list, + result_start_time, + ) + return {"message": "Scheme simulation results stored successfully"} + + +@router.get("/scheme/query/by-scheme-time-property") +async def query_scheme_records_by_scheme_time_property( + scheme_type: str, + scheme_name: str, + query_time: str, + type: str, + property: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + """Query all scheme records by scheme, time and property""" + try: + results = await SchemeRepository.query_all_record_by_scheme_time_property( + conn, scheme_type, scheme_name, query_time, type, property + ) + return {"results": results} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + +@router.get("/scheme/query/by-id-time") +async def query_scheme_simulation_by_id_time( + scheme_type: str, + scheme_name: str, + id: str, + type: str, + query_time: str, + conn: AsyncConnection = Depends(get_timescale_connection), +): + """Query scheme simulation results by id and time""" + try: + result = await SchemeRepository.query_scheme_simulation_result_by_id_time( + conn, scheme_type, scheme_name, id, type, query_time + ) + return {"result": result} + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) diff --git a/app/api/v1/endpoints/user_management.py b/app/api/v1/endpoints/user_management.py new file mode 100644 index 0000000..8109ec3 --- /dev/null +++ b/app/api/v1/endpoints/user_management.py @@ -0,0 +1,180 @@ +""" +用户管理 API 接口 + +演示权限控制的使用 +""" +from typing import List +from fastapi import APIRouter, Depends, HTTPException, status +from app.domain.schemas.user import UserResponse, UserUpdate, UserCreate +from app.domain.models.role import UserRole +from app.domain.schemas.user import UserInDB +from app.infra.repositories.user_repository import UserRepository +from app.auth.dependencies import get_user_repository, get_current_active_user +from app.auth.permissions import get_current_admin, require_role, check_resource_owner + +router = APIRouter() + +@router.get("/", response_model=List[UserResponse]) +async def list_users( + skip: int = 0, + limit: int = 100, + current_user: UserInDB = Depends(require_role(UserRole.ADMIN)), + user_repo: UserRepository = Depends(get_user_repository) +) -> List[UserResponse]: + """ + 获取用户列表(仅管理员) + """ + users = await user_repo.get_all_users(skip=skip, limit=limit) + return [UserResponse.model_validate(user) for user in users] + +@router.get("/{user_id}", response_model=UserResponse) +async def get_user( + user_id: int, + current_user: UserInDB = Depends(get_current_active_user), + user_repo: UserRepository = Depends(get_user_repository) +) -> UserResponse: + """ + 获取用户详情 + + 管理员可查看所有用户,普通用户只能查看自己 + """ + # 检查权限 + if not check_resource_owner(user_id, current_user): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="You don't have permission to view this user" + ) + + user = await user_repo.get_user_by_id(user_id) + if not user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + return UserResponse.model_validate(user) + +@router.put("/{user_id}", response_model=UserResponse) +async def update_user( + user_id: int, + user_update: UserUpdate, + current_user: UserInDB = Depends(get_current_active_user), + user_repo: UserRepository = Depends(get_user_repository) +) -> UserResponse: + """ + 更新用户信息 + + 管理员可更新所有用户,普通用户只能更新自己(且不能修改角色) + """ + # 检查用户是否存在 + target_user = await user_repo.get_user_by_id(user_id) + if not target_user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + # 权限检查 + is_owner = current_user.id == user_id + is_admin = UserRole(current_user.role).has_permission(UserRole.ADMIN) + + if not is_owner and not is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="You don't have permission to update this user" + ) + + # 非管理员不能修改角色和激活状态 + if not is_admin: + if user_update.role is not None: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Only admins can change user roles" + ) + if user_update.is_active is not None: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Only admins can change user active status" + ) + + # 更新用户 + updated_user = await user_repo.update_user(user_id, user_update) + if not updated_user: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to update user" + ) + + return UserResponse.model_validate(updated_user) + +@router.delete("/{user_id}") +async def delete_user( + user_id: int, + current_user: UserInDB = Depends(get_current_admin), + user_repo: UserRepository = Depends(get_user_repository) +) -> dict: + """ + 删除用户(仅管理员) + """ + # 不能删除自己 + if current_user.id == user_id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="You cannot delete your own account" + ) + + success = await user_repo.delete_user(user_id) + if not success: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + return {"message": "User deleted successfully"} + +@router.post("/{user_id}/activate") +async def activate_user( + user_id: int, + current_user: UserInDB = Depends(get_current_admin), + user_repo: UserRepository = Depends(get_user_repository) +) -> UserResponse: + """ + 激活用户(仅管理员) + """ + user_update = UserUpdate(is_active=True) + updated_user = await user_repo.update_user(user_id, user_update) + + if not updated_user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + return UserResponse.model_validate(updated_user) + +@router.post("/{user_id}/deactivate") +async def deactivate_user( + user_id: int, + current_user: UserInDB = Depends(get_current_admin), + user_repo: UserRepository = Depends(get_user_repository) +) -> UserResponse: + """ + 停用用户(仅管理员) + """ + # 不能停用自己 + if current_user.id == user_id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="You cannot deactivate your own account" + ) + + user_update = UserUpdate(is_active=False) + updated_user = await user_repo.update_user(user_id, user_update) + + if not updated_user: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="User not found" + ) + + return UserResponse.model_validate(updated_user) diff --git a/app/api/v1/endpoints/users.py b/app/api/v1/endpoints/users.py new file mode 100644 index 0000000..fd98cdc --- /dev/null +++ b/app/api/v1/endpoints/users.py @@ -0,0 +1,21 @@ +from fastapi import APIRouter, Request +from typing import Any, List, Dict, Union +from app.services.tjnetwork import Any, get_all_users, get_user, get_user_schema + +router = APIRouter() + +########################################################### +# user 39 +########################################################### + +@router.get("/getuserschema/") +async def fastapi_get_user_schema(network: str) -> dict[str, dict[Any, Any]]: + return get_user_schema(network) + +@router.get("/getuser/") +async def fastapi_get_user(network: str, user_name: str) -> dict[Any, Any]: + return get_user(network, user_name) + +@router.get("/getallusers/") +async def fastapi_get_all_users(network: str) -> list[dict[Any, Any]]: + return get_all_users(network) \ No newline at end of file diff --git a/app/api/v1/router.py b/app/api/v1/router.py new file mode 100644 index 0000000..53a6125 --- /dev/null +++ b/app/api/v1/router.py @@ -0,0 +1,112 @@ +from fastapi import APIRouter +from app.api.v1.endpoints import ( + auth, + project, + simulation, + scada, + extension, + snapshots, + data_query, + users, + schemes, + misc, + risk, + cache, + leakage, + burst_detection, + burst_location, + user_management, # 新增:用户管理 + audit, # 新增:审计日志 + meta, +) +from app.api.v1.endpoints.network import ( + general, + junctions, + reservoirs, + tanks, + pipes, + pumps, + valves, + tags, + demands, + geometry, + regions, +) +from app.api.v1.endpoints.components import ( + curves, + patterns, + controls, + options, + quality, + visuals, +) + +from app.api.v1.endpoints import project_data +from app.api.v1.endpoints.timeseries import ( + realtime as ts_realtime, + scheme as ts_scheme, + scada as ts_scada, + composite as ts_composite, +) + +api_router = APIRouter() + +# Core Services +api_router.include_router(auth.router, prefix="/auth", tags=["Auth"]) +api_router.include_router(user_management.router, prefix="/users", tags=["User Management"]) # 新增 +api_router.include_router(audit.router, prefix="/audit", tags=["Audit Logs"]) # 新增 +api_router.include_router(meta.router, tags=["Metadata"]) +api_router.include_router(project.router, tags=["Project"]) + +# Network Elements (Node/Link Types) +api_router.include_router(general.router, tags=["Network General"]) +api_router.include_router(junctions.router, tags=["Junctions"]) +api_router.include_router(reservoirs.router, tags=["Reservoirs"]) +api_router.include_router(tanks.router, tags=["Tanks"]) +api_router.include_router(pipes.router, tags=["Pipes"]) +api_router.include_router(pumps.router, tags=["Pumps"]) +api_router.include_router(valves.router, tags=["Valves"]) + +# Network Features +api_router.include_router(tags.router, tags=["Tags"]) +api_router.include_router(demands.router, tags=["Demands"]) +api_router.include_router(geometry.router, tags=["Geometry & Coordinates"]) +api_router.include_router(regions.router, tags=["Regions & DMAs"]) + +# Components & Controls +api_router.include_router(curves.router, tags=["Curves"]) +api_router.include_router(patterns.router, tags=["Patterns"]) +api_router.include_router(controls.router, tags=["Controls & Rules"]) +api_router.include_router(options.router, tags=["Options"]) +api_router.include_router(quality.router, tags=["Quality"]) +api_router.include_router(visuals.router, tags=["Visuals"]) + +# Simulation & Data +api_router.include_router(simulation.router, tags=["Simulation Control"]) +api_router.include_router(data_query.router, tags=["Data Query & InfluxDB"]) +api_router.include_router(scada.router, tags=["SCADA"]) +api_router.include_router(snapshots.router, tags=["Snapshots"]) +api_router.include_router(users.router, tags=["Users"]) +api_router.include_router(schemes.router, tags=["Schemes"]) +api_router.include_router(misc.router, tags=["Misc"]) +api_router.include_router(risk.router, tags=["Risk"]) +api_router.include_router(cache.router, tags=["Cache"]) +api_router.include_router(leakage.router, prefix="/leakage", tags=["Leakage"]) +api_router.include_router( + burst_detection.router, prefix="/burst-detection", tags=["Burst Detection"] +) +api_router.include_router( + burst_location.router, prefix="/burst-location", tags=["Burst Location"] +) + +# TimescaleDB Data Access +api_router.include_router(ts_realtime.router, tags=["TimescaleDB - Realtime"]) +api_router.include_router(ts_scheme.router, tags=["TimescaleDB - Scheme"]) +api_router.include_router(ts_scada.router, tags=["TimescaleDB - SCADA"]) +api_router.include_router(ts_composite.router, tags=["TimescaleDB - Composite"]) + +# Project Data (PostgreSQL) +api_router.include_router(project_data.router, tags=["Project Data"]) + +# Extension +api_router.include_router(extension.router, tags=["Extension"]) diff --git a/app/audit/__init__.py b/app/audit/__init__.py new file mode 100644 index 0000000..a34fd31 --- /dev/null +++ b/app/audit/__init__.py @@ -0,0 +1,9 @@ +""" +This module is reserved for future implementation of audit logging and compliance features. + +Current implementation of audit logging can be found in `app.core.audit`. +Future expansion may include: +- Comprehensive audit trails for all system actions +- Compliance reporting (e.g., for industrial control systems) +- Anomaly detection in user behavior +""" diff --git a/app/auth/__init__.py b/app/auth/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/auth/dependencies.py b/app/auth/dependencies.py new file mode 100644 index 0000000..8b7bff3 --- /dev/null +++ b/app/auth/dependencies.py @@ -0,0 +1,100 @@ +from typing import Annotated, Optional +from fastapi import Depends, HTTPException, status, Request +from fastapi.security import OAuth2PasswordBearer +from jose import jwt, JWTError +from app.core.config import settings +from app.domain.schemas.user import UserInDB, TokenPayload +from app.infra.repositories.user_repository import UserRepository +from app.infra.db.postgresql.database import Database + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/auth/login") + + +# 数据库依赖 +async def get_db(request: Request) -> Database: + """ + 获取数据库实例 + + 从 FastAPI app.state 中获取在启动时初始化的数据库连接 + """ + if not hasattr(request.app.state, "db"): + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Database not initialized", + ) + return request.app.state.db + + +async def get_user_repository(db: Database = Depends(get_db)) -> UserRepository: + """获取用户仓储实例""" + return UserRepository(db) + + +async def get_current_user( + token: str = Depends(oauth2_scheme), + user_repo: UserRepository = Depends(get_user_repository), +) -> UserInDB: + """ + 获取当前登录用户 + + 从 JWT Token 中解析用户信息,并从数据库验证 + """ + credentials_exception = HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Could not validate credentials", + headers={"WWW-Authenticate": "Bearer"}, + ) + + try: + payload = jwt.decode( + token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] + ) + username: str = payload.get("sub") + token_type: str = payload.get("type", "access") + + if username is None: + raise credentials_exception + + if token_type != "access": + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid token type. Access token required.", + headers={"WWW-Authenticate": "Bearer"}, + ) + + except JWTError: + raise credentials_exception + + # 从数据库获取用户 + user = await user_repo.get_user_by_username(username) + if user is None: + raise credentials_exception + + return user + + +async def get_current_active_user( + current_user: UserInDB = Depends(get_current_user), +) -> UserInDB: + """ + 获取当前活跃用户(必须是激活状态) + """ + if not current_user.is_active: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Inactive user" + ) + return current_user + + +async def get_current_superuser( + current_user: UserInDB = Depends(get_current_user), +) -> UserInDB: + """ + 获取当前超级管理员用户 + """ + if not current_user.is_superuser: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Not enough privileges. Superuser access required.", + ) + return current_user diff --git a/app/auth/keycloak_dependencies.py b/app/auth/keycloak_dependencies.py new file mode 100644 index 0000000..6b34936 --- /dev/null +++ b/app/auth/keycloak_dependencies.py @@ -0,0 +1,103 @@ +# import logging +from uuid import UUID + +from fastapi import Depends, HTTPException, status +from fastapi.security import OAuth2PasswordBearer +from jose import JWTError, jwt + +from app.core.config import settings + +oauth2_optional = OAuth2PasswordBearer( + tokenUrl=f"{settings.API_V1_STR}/auth/login", auto_error=False +) + +# logger = logging.getLogger(__name__) + + +async def get_current_keycloak_sub( + token: str | None = Depends(oauth2_optional), +) -> UUID: + if not token: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Not authenticated", + headers={"WWW-Authenticate": "Bearer"}, + ) + if settings.KEYCLOAK_PUBLIC_KEY: + key = settings.KEYCLOAK_PUBLIC_KEY.replace("\\n", "\n") + algorithms = [settings.KEYCLOAK_ALGORITHM] + else: + key = settings.SECRET_KEY + algorithms = [settings.ALGORITHM] + + try: + payload = jwt.decode( + token, + key, + algorithms=algorithms, + audience=settings.KEYCLOAK_AUDIENCE or None, + ) + except JWTError as exc: + # logger.warning("Keycloak token validation failed: %s", exc) + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid token", + headers={"WWW-Authenticate": "Bearer"}, + ) from exc + + sub = payload.get("sub") + if not sub: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Missing subject claim", + headers={"WWW-Authenticate": "Bearer"}, + ) + + try: + return UUID(sub) + except ValueError as exc: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid subject claim", + headers={"WWW-Authenticate": "Bearer"}, + ) from exc + + +async def get_current_keycloak_username( + token: str | None = Depends(oauth2_optional), +) -> str: + if not token: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Not authenticated", + headers={"WWW-Authenticate": "Bearer"}, + ) + if settings.KEYCLOAK_PUBLIC_KEY: + key = settings.KEYCLOAK_PUBLIC_KEY.replace("\\n", "\n") + algorithms = [settings.KEYCLOAK_ALGORITHM] + else: + key = settings.SECRET_KEY + algorithms = [settings.ALGORITHM] + + try: + payload = jwt.decode( + token, + key, + algorithms=algorithms, + audience=settings.KEYCLOAK_AUDIENCE or None, + ) + except JWTError as exc: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Invalid token", + headers={"WWW-Authenticate": "Bearer"}, + ) from exc + + username = payload.get("preferred_username") or payload.get("username") + if not username: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Missing username claim", + headers={"WWW-Authenticate": "Bearer"}, + ) + return str(username) diff --git a/app/auth/metadata_dependencies.py b/app/auth/metadata_dependencies.py new file mode 100644 index 0000000..7846396 --- /dev/null +++ b/app/auth/metadata_dependencies.py @@ -0,0 +1,60 @@ +from dataclasses import dataclass +from uuid import UUID + +import logging +from fastapi import Depends, HTTPException, status +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.ext.asyncio import AsyncSession + +from app.auth.keycloak_dependencies import get_current_keycloak_sub +from app.core.config import settings +from app.infra.db.metadata.database import get_metadata_session +from app.infra.repositories.metadata_repository import MetadataRepository + +logger = logging.getLogger(__name__) + + +async def get_metadata_repository( + session: AsyncSession = Depends(get_metadata_session), +) -> MetadataRepository: + return MetadataRepository(session) + + +async def get_current_metadata_user( + keycloak_sub: UUID = Depends(get_current_keycloak_sub), + metadata_repo: MetadataRepository = Depends(get_metadata_repository), +): + try: + user = await metadata_repo.get_user_by_keycloak_id(keycloak_sub) + except SQLAlchemyError as exc: + logger.error( + "Metadata DB error while resolving current user", + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Metadata database error: {exc}", + ) from exc + if not user or not user.is_active: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Inactive user" + ) + return user + + +async def get_current_metadata_admin( + user=Depends(get_current_metadata_user), +): + if user.is_superuser or user.role == "admin": + return user + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required" + ) + + +@dataclass(frozen=True) +class _AuthBypassUser: + id: UUID = UUID(int=0) + role: str = "admin" + is_superuser: bool = True + is_active: bool = True diff --git a/app/auth/permissions.py b/app/auth/permissions.py new file mode 100644 index 0000000..0fb8d1c --- /dev/null +++ b/app/auth/permissions.py @@ -0,0 +1,106 @@ +""" +权限控制依赖项和装饰器 + +基于角色的访问控制(RBAC) +""" +from typing import Callable +from fastapi import Depends, HTTPException, status +from app.domain.models.role import UserRole +from app.domain.schemas.user import UserInDB +from app.auth.dependencies import get_current_active_user + +def require_role(required_role: UserRole): + """ + 要求特定角色或更高权限 + + 用法: + @router.get("/admin-only") + async def admin_endpoint(user: UserInDB = Depends(require_role(UserRole.ADMIN))): + ... + + Args: + required_role: 需要的最低角色 + + Returns: + 依赖函数 + """ + async def role_checker( + current_user: UserInDB = Depends(get_current_active_user) + ) -> UserInDB: + user_role = UserRole(current_user.role) + + if not user_role.has_permission(required_role): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=f"Insufficient permissions. Required role: {required_role.value}, " + f"Your role: {user_role.value}" + ) + + return current_user + + return role_checker + +# 预定义的权限检查依赖 +require_admin = require_role(UserRole.ADMIN) +require_operator = require_role(UserRole.OPERATOR) +require_user = require_role(UserRole.USER) + +def get_current_admin( + current_user: UserInDB = Depends(require_admin) +) -> UserInDB: + """ + 获取当前管理员用户 + + 等同于 Depends(require_role(UserRole.ADMIN)) + """ + return current_user + +def get_current_operator( + current_user: UserInDB = Depends(require_operator) +) -> UserInDB: + """ + 获取当前操作员用户(或更高权限) + + 等同于 Depends(require_role(UserRole.OPERATOR)) + """ + return current_user + +def check_resource_owner(user_id: int, current_user: UserInDB) -> bool: + """ + 检查是否是资源拥有者或管理员 + + Args: + user_id: 资源拥有者ID + current_user: 当前用户 + + Returns: + 是否有权限 + """ + # 管理员可以访问所有资源 + if UserRole(current_user.role).has_permission(UserRole.ADMIN): + return True + + # 检查是否是资源拥有者 + return current_user.id == user_id + +def require_owner_or_admin(user_id: int): + """ + 要求是资源拥有者或管理员 + + Args: + user_id: 资源拥有者ID + + Returns: + 依赖函数 + """ + async def owner_or_admin_checker( + current_user: UserInDB = Depends(get_current_active_user) + ) -> UserInDB: + if not check_resource_owner(user_id, current_user): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="You don't have permission to access this resource" + ) + return current_user + + return owner_or_admin_checker diff --git a/app/auth/project_dependencies.py b/app/auth/project_dependencies.py new file mode 100644 index 0000000..a1d68df --- /dev/null +++ b/app/auth/project_dependencies.py @@ -0,0 +1,213 @@ +from dataclasses import dataclass +from typing import AsyncGenerator +from uuid import UUID + +import logging +from fastapi import Depends, Header, HTTPException, status +from psycopg import AsyncConnection +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.ext.asyncio import AsyncSession + +from app.auth.keycloak_dependencies import get_current_keycloak_sub +from app.core.config import settings +from app.infra.db.dynamic_manager import project_connection_manager +from app.infra.db.metadata.database import get_metadata_session +from app.infra.repositories.metadata_repository import MetadataRepository + +DB_ROLE_BIZ_DATA = "biz_data" +DB_ROLE_IOT_DATA = "iot_data" +DB_TYPE_POSTGRES = "postgresql" +DB_TYPE_TIMESCALE = "timescaledb" + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class ProjectContext: + project_id: UUID + user_id: UUID + project_role: str + + +async def get_metadata_repository( + session: AsyncSession = Depends(get_metadata_session), +) -> MetadataRepository: + return MetadataRepository(session) + + +async def get_project_context( + x_project_id: str = Header(..., alias="X-Project-Id"), + keycloak_sub: UUID = Depends(get_current_keycloak_sub), + metadata_repo: MetadataRepository = Depends(get_metadata_repository), +) -> ProjectContext: + try: + project_uuid = UUID(x_project_id) + except ValueError as exc: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid project id" + ) from exc + + try: + project = await metadata_repo.get_project_by_id(project_uuid) + if not project: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Project not found" + ) + if project.status != "active": + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Project is not active" + ) + + user = await metadata_repo.get_user_by_keycloak_id(keycloak_sub) + if not user: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="User not registered" + ) + if not user.is_active: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Inactive user" + ) + + membership_role = await metadata_repo.get_membership_role(project_uuid, user.id) + if not membership_role: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="No access to project" + ) + except SQLAlchemyError as exc: + logger.error( + "Metadata DB error while resolving project context", + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Metadata database error: {exc}", + ) from exc + + return ProjectContext( + project_id=project.id, + user_id=user.id, + project_role=membership_role, + ) + + +async def get_project_pg_session( + ctx: ProjectContext = Depends(get_project_context), + metadata_repo: MetadataRepository = Depends(get_metadata_repository), +) -> AsyncGenerator[AsyncSession, None]: + try: + routing = await metadata_repo.get_project_db_routing( + ctx.project_id, DB_ROLE_BIZ_DATA + ) + except ValueError as exc: + logger.error( + "Invalid project PostgreSQL routing DSN configuration", + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Project PostgreSQL routing DSN is invalid: {exc}", + ) from exc + if not routing: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Project PostgreSQL not configured", + ) + if routing.db_type != DB_TYPE_POSTGRES: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Project PostgreSQL type mismatch", + ) + + pool_min_size = routing.pool_min_size or settings.PROJECT_PG_POOL_SIZE + pool_max_size = routing.pool_max_size or settings.PROJECT_PG_POOL_SIZE + sessionmaker = await project_connection_manager.get_pg_sessionmaker( + ctx.project_id, + DB_ROLE_BIZ_DATA, + routing.dsn, + pool_min_size, + pool_max_size, + ) + async with sessionmaker() as session: + yield session + + +async def get_project_pg_connection( + ctx: ProjectContext = Depends(get_project_context), + metadata_repo: MetadataRepository = Depends(get_metadata_repository), +) -> AsyncGenerator[AsyncConnection, None]: + try: + routing = await metadata_repo.get_project_db_routing( + ctx.project_id, DB_ROLE_BIZ_DATA + ) + except ValueError as exc: + logger.error( + "Invalid project PostgreSQL routing DSN configuration", + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Project PostgreSQL routing DSN is invalid: {exc}", + ) from exc + if not routing: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Project PostgreSQL not configured", + ) + if routing.db_type != DB_TYPE_POSTGRES: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Project PostgreSQL type mismatch", + ) + + pool_min_size = routing.pool_min_size or settings.PROJECT_PG_POOL_SIZE + pool_max_size = routing.pool_max_size or settings.PROJECT_PG_POOL_SIZE + pool = await project_connection_manager.get_pg_pool( + ctx.project_id, + DB_ROLE_BIZ_DATA, + routing.dsn, + pool_min_size, + pool_max_size, + ) + async with pool.connection() as conn: + yield conn + + +async def get_project_timescale_connection( + ctx: ProjectContext = Depends(get_project_context), + metadata_repo: MetadataRepository = Depends(get_metadata_repository), +) -> AsyncGenerator[AsyncConnection, None]: + try: + routing = await metadata_repo.get_project_db_routing( + ctx.project_id, DB_ROLE_IOT_DATA + ) + except ValueError as exc: + logger.error( + "Invalid project TimescaleDB routing DSN configuration", + exc_info=True, + ) + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Project TimescaleDB routing DSN is invalid: {exc}", + ) from exc + if not routing: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Project TimescaleDB not configured", + ) + if routing.db_type != DB_TYPE_TIMESCALE: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail="Project TimescaleDB type mismatch", + ) + + pool_min_size = routing.pool_min_size or settings.PROJECT_TS_POOL_MIN_SIZE + pool_max_size = routing.pool_max_size or settings.PROJECT_TS_POOL_MAX_SIZE + pool = await project_connection_manager.get_timescale_pool( + ctx.project_id, + DB_ROLE_IOT_DATA, + routing.dsn, + pool_min_size, + pool_max_size, + ) + async with pool.connection() as conn: + yield conn diff --git a/app/core/__init__.py b/app/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/core/audit.py b/app/core/audit.py new file mode 100644 index 0000000..b3f96eb --- /dev/null +++ b/app/core/audit.py @@ -0,0 +1,146 @@ +""" +审计日志模块 + +记录系统关键操作,用于安全审计和合规追踪 +""" + +from typing import Optional +from datetime import datetime +import logging +from uuid import UUID + +logger = logging.getLogger(__name__) + + +class AuditAction: + """审计操作类型常量""" + + # 认证相关 + LOGIN = "LOGIN" + LOGOUT = "LOGOUT" + REGISTER = "REGISTER" + PASSWORD_CHANGE = "PASSWORD_CHANGE" + + # 数据操作 + CREATE = "CREATE" + READ = "READ" + UPDATE = "UPDATE" + DELETE = "DELETE" + + # 权限相关 + PERMISSION_CHANGE = "PERMISSION_CHANGE" + ROLE_CHANGE = "ROLE_CHANGE" + + # 系统操作 + CONFIG_CHANGE = "CONFIG_CHANGE" + SYSTEM_START = "SYSTEM_START" + SYSTEM_STOP = "SYSTEM_STOP" + + +async def log_audit_event( + action: str, + user_id: Optional[UUID] = None, + project_id: Optional[UUID] = None, + resource_type: Optional[str] = None, + resource_id: Optional[str] = None, + ip_address: Optional[str] = None, + request_method: Optional[str] = None, + request_path: Optional[str] = None, + request_data: Optional[dict] = None, + response_status: Optional[int] = None, + session=None, +): + """ + 记录审计日志 + + Args: + action: 操作类型 + user_id: 用户ID + project_id: 项目ID + resource_type: 资源类型 + resource_id: 资源ID + ip_address: IP地址 + request_method: 请求方法 + request_path: 请求路径 + request_data: 请求数据(敏感字段需脱敏) + response_status: 响应状态码 + session: 元数据库会话(可选) + """ + from app.infra.db.metadata.database import SessionLocal + from app.infra.repositories.audit_repository import AuditRepository + + if request_data: + request_data = sanitize_sensitive_data(request_data) + + if session is None: + async with SessionLocal() as session: + audit_repo = AuditRepository(session) + await audit_repo.create_log( + user_id=user_id, + project_id=project_id, + action=action, + resource_type=resource_type, + resource_id=resource_id, + ip_address=ip_address, + request_method=request_method, + request_path=request_path, + request_data=request_data, + response_status=response_status, + ) + else: + audit_repo = AuditRepository(session) + await audit_repo.create_log( + user_id=user_id, + project_id=project_id, + action=action, + resource_type=resource_type, + resource_id=resource_id, + ip_address=ip_address, + request_method=request_method, + request_path=request_path, + request_data=request_data, + response_status=response_status, + ) + + logger.info( + "Audit log created: action=%s, user=%s, project=%s, resource=%s:%s", + action, + user_id, + project_id, + resource_type, + resource_id, + ) + + +def sanitize_sensitive_data(data: dict) -> dict: + """ + 脱敏敏感数据 + + Args: + data: 原始数据 + + Returns: + 脱敏后的数据 + """ + sensitive_fields = [ + "password", + "passwd", + "pwd", + "secret", + "token", + "api_key", + "apikey", + "credit_card", + "ssn", + "social_security", + ] + + sanitized = data.copy() + + for key in sanitized: + if isinstance(sanitized[key], dict): + sanitized[key] = sanitize_sensitive_data(sanitized[key]) + elif any(sensitive in key.lower() for sensitive in sensitive_fields): + sanitized[key] = "***REDACTED***" + + return sanitized diff --git a/app/core/config.py b/app/core/config.py new file mode 100644 index 0000000..58e79c2 --- /dev/null +++ b/app/core/config.py @@ -0,0 +1,118 @@ +from pathlib import Path +from typing import Optional +from urllib.parse import quote_plus +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + PROJECT_NAME: str = "TJWater Server" + ENVIRONMENT: str = "local" + API_V1_STR: str = "/api/v1" + + # JWT 配置 + SECRET_KEY: str = ( + "your-secret-key-here-change-in-production-use-openssl-rand-hex-32" + ) + ALGORITHM: str = "HS256" + ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 + REFRESH_TOKEN_EXPIRE_DAYS: int = 7 + + # 数据加密密钥 (使用 Fernet) + ENCRYPTION_KEY: str = "" # 必须从环境变量设置 + DATABASE_ENCRYPTION_KEY: str = "" # project_databases.dsn_encrypted 专用 + + # Database Config (PostgreSQL) + DB_NAME: str = "tjwater" + DB_HOST: str = "localhost" + DB_PORT: str = "5432" + DB_USER: str = "postgres" + DB_PASSWORD: str = "password" + + # Database Config (TimescaleDB) + TIMESCALEDB_DB_NAME: str = "tjwater" + TIMESCALEDB_DB_HOST: str = "localhost" + TIMESCALEDB_DB_PORT: str = "5433" + TIMESCALEDB_DB_USER: str = "postgres" + TIMESCALEDB_DB_PASSWORD: str = "password" + # InfluxDB + INFLUXDB_URL: str = "http://localhost:8086" + INFLUXDB_TOKEN: str = "token" + INFLUXDB_ORG: str = "org" + INFLUXDB_BUCKET: str = "bucket" + + # Metadata Database Config (PostgreSQL) + METADATA_DB_NAME: str = "system_hub" + METADATA_DB_HOST: str = "localhost" + METADATA_DB_PORT: str = "5432" + METADATA_DB_USER: str = "postgres" + METADATA_DB_PASSWORD: str = "password" + + METADATA_DB_POOL_SIZE: int = 5 + METADATA_DB_MAX_OVERFLOW: int = 10 + + PROJECT_PG_CACHE_SIZE: int = 50 + PROJECT_TS_CACHE_SIZE: int = 50 + PROJECT_PG_POOL_SIZE: int = 5 + PROJECT_PG_MAX_OVERFLOW: int = 10 + PROJECT_TS_POOL_MIN_SIZE: int = 1 + PROJECT_TS_POOL_MAX_SIZE: int = 10 + + # Keycloak JWT (optional override) + KEYCLOAK_PUBLIC_KEY: str = "" + KEYCLOAK_ALGORITHM: str = "RS256" + KEYCLOAK_AUDIENCE: str = "" + + @property + def SQLALCHEMY_DATABASE_URI(self) -> str: + db_password = quote_plus(self.DB_PASSWORD) + return f"postgresql://{self.DB_USER}:{db_password}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}" + + @property + def METADATA_DATABASE_URI(self) -> str: + metadata_password = quote_plus(self.METADATA_DB_PASSWORD) + return ( + f"postgresql+psycopg://{self.METADATA_DB_USER}:{metadata_password}" + f"@{self.METADATA_DB_HOST}:{self.METADATA_DB_PORT}/{self.METADATA_DB_NAME}" + ) + + model_config = SettingsConfigDict( + env_file=Path(__file__).resolve().parents[2] / ".env", + extra="ignore", + ) + + +settings = Settings() + + +def get_pgconn_string( + db_name: Optional[str] = None, + db_host: Optional[str] = None, + db_port: Optional[str] = None, + db_user: Optional[str] = None, + db_password: Optional[str] = None, +) -> str: + """Return PostgreSQL connection string in psycopg conninfo format.""" + resolved_db_name = db_name or settings.DB_NAME + resolved_db_host = db_host or settings.DB_HOST + resolved_db_port = db_port or settings.DB_PORT + resolved_db_user = db_user or settings.DB_USER + resolved_db_password = db_password or settings.DB_PASSWORD + return ( + f"dbname={resolved_db_name} host={resolved_db_host} port={resolved_db_port} " + f"user={resolved_db_user} password={resolved_db_password}" + ) + + +def get_pg_config() -> dict: + """Return PostgreSQL configuration except password.""" + return { + "name": settings.DB_NAME, + "host": settings.DB_HOST, + "port": settings.DB_PORT, + "user": settings.DB_USER, + } + + +def get_pg_password() -> str: + """Return PostgreSQL password (use with care).""" + return settings.DB_PASSWORD diff --git a/app/core/encryption.py b/app/core/encryption.py new file mode 100644 index 0000000..9b5f6c2 --- /dev/null +++ b/app/core/encryption.py @@ -0,0 +1,126 @@ +from cryptography.fernet import Fernet +from typing import Optional +import base64 +import os + +from app.core.config import settings + + +class Encryptor: + """ + 使用 Fernet (对称加密) 实现数据加密/解密 + 适用于加密敏感配置、用户数据等 + """ + + def __init__(self, key: Optional[bytes] = None): + """ + 初始化加密器 + + Args: + key: 加密密钥,如果为 None 则从环境变量读取 + """ + if key is None: + key_str = os.getenv("ENCRYPTION_KEY") or settings.ENCRYPTION_KEY + if not key_str: + raise ValueError( + "ENCRYPTION_KEY not found in environment variables or .env. " + "Generate one using: Encryptor.generate_key()" + ) + key = key_str.encode() + + self.fernet = Fernet(key) + + def encrypt(self, data: str) -> str: + """ + 加密字符串 + + Args: + data: 待加密的明文字符串 + + Returns: + Base64 编码的加密字符串 + """ + if not data: + return data + + encrypted_bytes = self.fernet.encrypt(data.encode()) + return encrypted_bytes.decode() + + def decrypt(self, data: str) -> str: + """ + 解密字符串 + + Args: + data: Base64 编码的加密字符串 + + Returns: + 解密后的明文字符串 + """ + if not data: + return data + + decrypted_bytes = self.fernet.decrypt(data.encode()) + return decrypted_bytes.decode() + + @staticmethod + def generate_key() -> str: + """ + 生成新的 Fernet 加密密钥 + + Returns: + Base64 编码的密钥字符串 + """ + key = Fernet.generate_key() + return key.decode() + + +# 全局加密器实例(懒加载) +_encryptor: Optional[Encryptor] = None +_database_encryptor: Optional[Encryptor] = None + + +def is_encryption_configured() -> bool: + return bool(os.getenv("ENCRYPTION_KEY") or settings.ENCRYPTION_KEY) + + +def is_database_encryption_configured() -> bool: + return bool( + os.getenv("DATABASE_ENCRYPTION_KEY") + or settings.DATABASE_ENCRYPTION_KEY + or os.getenv("ENCRYPTION_KEY") + or settings.ENCRYPTION_KEY + ) + + +def get_encryptor() -> Encryptor: + """获取全局加密器实例""" + global _encryptor + if _encryptor is None: + _encryptor = Encryptor() + return _encryptor + + +def get_database_encryptor() -> Encryptor: + """获取 project DB DSN 专用加密器实例""" + global _database_encryptor + if _database_encryptor is None: + key_str = ( + os.getenv("DATABASE_ENCRYPTION_KEY") + or settings.DATABASE_ENCRYPTION_KEY + or os.getenv("ENCRYPTION_KEY") + or settings.ENCRYPTION_KEY + ) + if not key_str: + raise ValueError( + "DATABASE_ENCRYPTION_KEY not found in environment variables or .env. " + "Generate one using: Encryptor.generate_key()" + ) + _database_encryptor = Encryptor(key=key_str.encode()) + return _database_encryptor + + +# 向后兼容(延迟加载) +def __getattr__(name): + if name == "encryptor": + return get_encryptor() + raise AttributeError(f"module '{__name__}' has no attribute '{name}'") diff --git a/app/core/security.py b/app/core/security.py new file mode 100644 index 0000000..802e837 --- /dev/null +++ b/app/core/security.py @@ -0,0 +1,91 @@ +from datetime import datetime, timedelta +from typing import Optional, Union, Any + +from jose import jwt +from passlib.context import CryptContext +from app.core.config import settings + +pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") + + +def create_access_token( + subject: Union[str, Any], expires_delta: Optional[timedelta] = None +) -> str: + """ + 创建 JWT Access Token + + Args: + subject: 用户标识(通常是用户名或用户ID) + expires_delta: 过期时间增量 + + Returns: + JWT token 字符串 + """ + if expires_delta: + expire = datetime.now() + expires_delta + else: + expire = datetime.now() + timedelta( + minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES + ) + + to_encode = { + "exp": expire, + "sub": str(subject), + "type": "access", + "iat": datetime.now(), + } + encoded_jwt = jwt.encode( + to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM + ) + return encoded_jwt + + +def create_refresh_token(subject: Union[str, Any]) -> str: + """ + 创建 JWT Refresh Token(长期有效) + + Args: + subject: 用户标识 + + Returns: + JWT refresh token 字符串 + """ + expire = datetime.now() + timedelta(days=settings.REFRESH_TOKEN_EXPIRE_DAYS) + + to_encode = { + "exp": expire, + "sub": str(subject), + "type": "refresh", + "iat": datetime.now(), + } + encoded_jwt = jwt.encode( + to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM + ) + return encoded_jwt + + +def verify_password(plain_password: str, hashed_password: str) -> bool: + """ + 验证密码 + + Args: + plain_password: 明文密码 + hashed_password: 密码哈希 + + Returns: + 是否匹配 + """ + return pwd_context.verify(plain_password, hashed_password) + + +def get_password_hash(password: str) -> str: + """ + 生成密码哈希 + + Args: + password: 明文密码 + + Returns: + bcrypt 哈希字符串 + """ + return pwd_context.hash(password) diff --git a/app/crypto/__init__.py b/app/crypto/__init__.py new file mode 100644 index 0000000..868dc25 --- /dev/null +++ b/app/crypto/__init__.py @@ -0,0 +1,10 @@ +""" +This module is reserved for future implementation of advanced cryptographic operations. + +Current basic encryption (Fernet) and password hashing are implemented in `app.core.encryption` and `app.core.security`. +Future expansion may include: +- Asymmetric encryption (RSA/ECC) for secure communication +- Key management and rotation services +- Integration with Hardware Security Modules (HSM) +- Digital signatures for data integrity verification +""" diff --git a/app/domain/__init__.py b/app/domain/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/domain/models/__init__.py b/app/domain/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/domain/models/role.py b/app/domain/models/role.py new file mode 100644 index 0000000..1870bf8 --- /dev/null +++ b/app/domain/models/role.py @@ -0,0 +1,36 @@ +from enum import Enum + +class UserRole(str, Enum): + """用户角色枚举""" + ADMIN = "ADMIN" # 管理员 - 完全权限 + OPERATOR = "OPERATOR" # 操作员 - 可修改数据 + USER = "USER" # 普通用户 - 读写权限 + VIEWER = "VIEWER" # 观察者 - 仅查询权限 + + def __str__(self): + return self.value + + @classmethod + def get_hierarchy(cls) -> dict: + """ + 获取角色层级(数字越大权限越高) + """ + return { + cls.VIEWER: 1, + cls.USER: 2, + cls.OPERATOR: 3, + cls.ADMIN: 4, + } + + def has_permission(self, required_role: 'UserRole') -> bool: + """ + 检查当前角色是否有足够权限 + + Args: + required_role: 需要的最低角色 + + Returns: + True if has permission + """ + hierarchy = self.get_hierarchy() + return hierarchy[self] >= hierarchy[required_role] diff --git a/app/domain/schemas/__init__.py b/app/domain/schemas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/domain/schemas/audit.py b/app/domain/schemas/audit.py new file mode 100644 index 0000000..86b8b5a --- /dev/null +++ b/app/domain/schemas/audit.py @@ -0,0 +1,45 @@ +from datetime import datetime +from typing import Optional +from uuid import UUID +from pydantic import BaseModel, ConfigDict, Field + +class AuditLogCreate(BaseModel): + """创建审计日志""" + user_id: Optional[UUID] = None + project_id: Optional[UUID] = None + action: str + resource_type: Optional[str] = None + resource_id: Optional[str] = None + ip_address: Optional[str] = None + request_method: Optional[str] = None + request_path: Optional[str] = None + request_data: Optional[dict] = None + response_status: Optional[int] = None + +class AuditLogResponse(BaseModel): + """审计日志响应""" + id: UUID + user_id: Optional[UUID] + project_id: Optional[UUID] + action: str + resource_type: Optional[str] + resource_id: Optional[str] + ip_address: Optional[str] + request_method: Optional[str] + request_path: Optional[str] + request_data: Optional[dict] + response_status: Optional[int] + timestamp: datetime + + model_config = ConfigDict(from_attributes=True) + +class AuditLogQuery(BaseModel): + """审计日志查询参数""" + user_id: Optional[UUID] = None + project_id: Optional[UUID] = None + action: Optional[str] = None + resource_type: Optional[str] = None + start_time: Optional[datetime] = None + end_time: Optional[datetime] = None + skip: int = Field(default=0, ge=0) + limit: int = Field(default=100, ge=1, le=1000) diff --git a/app/domain/schemas/metadata.py b/app/domain/schemas/metadata.py new file mode 100644 index 0000000..b3f4952 --- /dev/null +++ b/app/domain/schemas/metadata.py @@ -0,0 +1,33 @@ +from typing import Optional +from uuid import UUID + +from pydantic import BaseModel + + +class GeoServerConfigResponse(BaseModel): + gs_base_url: Optional[str] + gs_admin_user: Optional[str] + gs_datastore_name: str + default_extent: Optional[dict] + srid: int + + +class ProjectMetaResponse(BaseModel): + project_id: UUID + name: str + code: str + description: Optional[str] + gs_workspace: str + status: str + project_role: str + geoserver: Optional[GeoServerConfigResponse] + + +class ProjectSummaryResponse(BaseModel): + project_id: UUID + name: str + code: str + description: Optional[str] + gs_workspace: str + status: str + project_role: str diff --git a/app/domain/schemas/user.py b/app/domain/schemas/user.py new file mode 100644 index 0000000..864035a --- /dev/null +++ b/app/domain/schemas/user.py @@ -0,0 +1,68 @@ +from datetime import datetime +from typing import Optional +from pydantic import BaseModel, EmailStr, Field, ConfigDict +from app.domain.models.role import UserRole + +# ============================================ +# Request Schemas (输入) +# ============================================ + +class UserCreate(BaseModel): + """用户注册""" + username: str = Field(..., min_length=3, max_length=50, + description="用户名,3-50个字符") + email: EmailStr = Field(..., description="邮箱地址") + password: str = Field(..., min_length=6, max_length=100, + description="密码,至少6个字符") + role: UserRole = Field(default=UserRole.USER, description="用户角色") + +class UserLogin(BaseModel): + """用户登录""" + username: str = Field(..., description="用户名或邮箱") + password: str = Field(..., description="密码") + +class UserUpdate(BaseModel): + """用户信息更新""" + email: Optional[EmailStr] = None + password: Optional[str] = Field(None, min_length=6, max_length=100) + role: Optional[UserRole] = None + is_active: Optional[bool] = None + +# ============================================ +# Response Schemas (输出) +# ============================================ + +class UserResponse(BaseModel): + """用户信息响应(不含密码)""" + id: int + username: str + email: str + role: UserRole + is_active: bool + is_superuser: bool + created_at: datetime + updated_at: datetime + + model_config = ConfigDict(from_attributes=True) + +class UserInDB(UserResponse): + """数据库中的用户(含密码哈希)""" + hashed_password: str + +# ============================================ +# Token Schemas +# ============================================ + +class Token(BaseModel): + """JWT Token 响应""" + access_token: str + refresh_token: Optional[str] = None + token_type: str = "bearer" + expires_in: int = Field(..., description="过期时间(秒)") + +class TokenPayload(BaseModel): + """JWT Token Payload""" + sub: str = Field(..., description="用户ID或用户名") + exp: Optional[int] = None + iat: Optional[int] = None + type: str = Field(default="access", description="token类型: access 或 refresh") diff --git a/app/infra/__init__.py b/app/infra/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/infra/audit/__init__.py b/app/infra/audit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/infra/audit/middleware.py b/app/infra/audit/middleware.py new file mode 100644 index 0000000..556f5e0 --- /dev/null +++ b/app/infra/audit/middleware.py @@ -0,0 +1,262 @@ +""" +审计日志中间件 + +自动记录关键HTTP请求到审计日志 +""" + +import time +import json +from uuid import UUID +from typing import Callable +from fastapi import Request, Response +from starlette.middleware.base import BaseHTTPMiddleware +from app.core.audit import log_audit_event, AuditAction +import logging +from jose import JWTError, jwt + +from app.core.config import settings +from app.infra.db.metadata.database import SessionLocal +from app.infra.repositories.metadata_repository import MetadataRepository + +logger = logging.getLogger(__name__) + + +class AuditMiddleware(BaseHTTPMiddleware): + """ + 审计中间件 + + 自动记录以下操作: + - 所有 POST/PUT/DELETE 请求 + - 登录/登出 + - 关键资源访问 + """ + + # 需要审计的路径前缀 + AUDIT_PATHS = [ + # "/api/v1/auth/", + # "/api/v1/users/", + # "/api/v1/projects/", + # "/api/v1/networks/", + ] + + # [新增] 需要审计的 API Tags (在 Router 或 api 函数中定义 tags=["Audit"]) + AUDIT_TAGS = [ + "Audit", + "Users", + "Project", + "Network General", + "Junctions", + "Pipes", + "Reservoirs", + "Tanks", + "Pumps", + "Valves", + ] + + # 需要审计的HTTP方法 + AUDIT_METHODS = ["POST", "PUT", "DELETE", "PATCH"] + EXCLUDED_PATHS = { + "/api/v1/meta/projects", + "/meta/projects", + "/api/v1/openproject/", + "/openproject/", + } + + async def dispatch(self, request: Request, call_next: Callable) -> Response: + # 提取开始时间 + start_time = time.time() + + # 1. 预判是否需要读取Body (针对写操作) + # 注意:我们暂时移除早期的 return,因为需要等待路由匹配后才能检查 Tag + should_capture_body = request.method in ["POST", "PUT", "PATCH"] + + request_data = None + if should_capture_body: + try: + # 注意:读取 body 后需要重新设置,避免影响后续处理 + body = await request.body() + if body: + request_data = json.loads(body.decode()) + + # 重新构造请求以供后续使用 + async def receive(): + return {"type": "http.request", "body": body} + + request._receive = receive + except Exception as e: + logger.warning(f"Failed to read request body for audit: {e}") + + # 2. 执行请求 (FastAPI在此过程中进行路由匹配) + response = await call_next(request) + + # 3. 决定是否审计 + if request.url.path in self.EXCLUDED_PATHS: + process_time = time.time() - start_time + response.headers["X-Process-Time"] = str(process_time) + return response + + # 检查方法 + is_audit_method = request.method in self.AUDIT_METHODS + # 检查路径 + is_audit_path = any( + request.url.path.startswith(path) for path in self.AUDIT_PATHS + ) + # [新增] 检查 Tags (从 request.scope 中获取匹配的路由信息) + is_audit_tag = False + route = request.scope.get("route") + if route and hasattr(route, "tags"): + is_audit_tag = any(tag in self.AUDIT_TAGS for tag in route.tags) + + should_audit = is_audit_method or is_audit_path or is_audit_tag + + if not should_audit: + # 即便不审计,也要处理响应头中的时间(保持原有逻辑一致性) + process_time = time.time() - start_time + response.headers["X-Process-Time"] = str(process_time) + return response + + # 4. 提取审计所需信息 + user_id = await self._resolve_user_id(request) + project_id = self._resolve_project_id(request) + + # 获取客户端信息 + ip_address = request.client.host if request.client else None + + # 确定操作类型 + action = self._determine_action(request) + resource_type, resource_id = self._extract_resource_info(request) + + # 记录审计日志 + try: + await log_audit_event( + action=action, + user_id=user_id, + project_id=project_id, + resource_type=resource_type, + resource_id=resource_id, + ip_address=ip_address, + request_method=request.method, + request_path=str(request.url.path), + request_data=request_data, + response_status=response.status_code, + ) + except Exception as e: + # 审计失败不应影响响应 + logger.error(f"Failed to log audit event: {e}", exc_info=True) + + # 添加处理时间到响应头 + process_time = time.time() - start_time + response.headers["X-Process-Time"] = str(process_time) + + return response + + def _resolve_project_id(self, request: Request) -> UUID | None: + project_header = request.headers.get("X-Project-Id") + if not project_header: + return None + try: + return UUID(project_header) + except ValueError: + return None + + async def _resolve_user_id(self, request: Request) -> UUID | None: + auth_header = request.headers.get("authorization") + if not auth_header or not auth_header.lower().startswith("bearer "): + return None + token = auth_header.split(" ", 1)[1].strip() + if not token: + return None + sub = None + try: + key = ( + settings.KEYCLOAK_PUBLIC_KEY.replace("\\n", "\n") + if settings.KEYCLOAK_PUBLIC_KEY + else settings.SECRET_KEY + ) + algorithms = ( + [settings.KEYCLOAK_ALGORITHM] + if settings.KEYCLOAK_PUBLIC_KEY + else [settings.ALGORITHM] + ) + payload = jwt.decode( + token, + key, + algorithms=algorithms, + audience=settings.KEYCLOAK_AUDIENCE or None, + ) + sub = payload.get("sub") + if not sub: + return None + except JWTError: + return None + + async with SessionLocal() as session: + repo = MetadataRepository(session) + try: + keycloak_id = UUID(sub) + user = await repo.get_user_by_keycloak_id(keycloak_id) + except ValueError: + user = await repo.get_user_by_username(sub) + if user and user.is_active: + return user.id + return None + + def _determine_action(self, request: Request) -> str: + """根据请求路径和方法确定操作类型""" + path = request.url.path.lower() + method = request.method + + # 认证相关 + if "login" in path: + return AuditAction.LOGIN + elif "logout" in path: + return AuditAction.LOGOUT + elif "register" in path: + return AuditAction.REGISTER + + # CRUD 操作 + if method == "POST": + return AuditAction.CREATE + elif method == "PUT" or method == "PATCH": + return AuditAction.UPDATE + elif method == "DELETE": + return AuditAction.DELETE + elif method == "GET": + return AuditAction.READ + + return f"{method}_REQUEST" + + def _extract_resource_info(self, request: Request) -> tuple: + """从请求路径提取资源类型和ID""" + path_parts = request.url.path.strip("/").split("/") + + resource_type = None + resource_id = None + + # 尝试从路径中提取资源信息 + # 例如: /api/v1/users/123 -> resource_type=user, resource_id=123 + if len(path_parts) >= 4: + resource_type = path_parts[3].rstrip("s") # 移除复数s + + if len(path_parts) >= 5 and path_parts[4]: + resource_id = path_parts[4] + + # 无路径ID时,尝试从查询参数提取业务ID + if not resource_id: + for key in ( + "id", + "resource_id", + "device_id", + "device_ids", + "element_id", + "user_id", + "project_id", + "network", + "name", + ): + value = request.query_params.get(key) + if value: + resource_id = value + break + + return resource_type, resource_id diff --git a/app/infra/cache/__init__.py b/app/infra/cache/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/infra/cache/redis_client.py b/app/infra/cache/redis_client.py new file mode 100644 index 0000000..c9b58f8 --- /dev/null +++ b/app/infra/cache/redis_client.py @@ -0,0 +1,19 @@ +import redis +import msgpack +from datetime import datetime +from typing import Any + +# Initialize Redis connection +redis_client = redis.Redis(host="127.0.0.1", port=6379, db=0) + +def encode_datetime(obj: Any) -> Any: + """Serialize datetime objects to dictionary format.""" + if isinstance(obj, datetime): + return {"__datetime__": True, "as_str": obj.strftime("%Y%m%dT%H:%M:%S.%f")} + return obj + +def decode_datetime(obj: Any) -> Any: + """Deserialize dictionary format to datetime objects.""" + if "__datetime__" in obj: + return datetime.strptime(obj["as_str"], "%Y%m%dT%H:%M:%S.%f") + return obj diff --git a/app/infra/db/__init__.py b/app/infra/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/infra/db/dynamic_manager.py b/app/infra/db/dynamic_manager.py new file mode 100644 index 0000000..094cbec --- /dev/null +++ b/app/infra/db/dynamic_manager.py @@ -0,0 +1,211 @@ +import asyncio +import logging +from collections import OrderedDict +from dataclasses import dataclass +from typing import Dict +from uuid import UUID + +from psycopg_pool import AsyncConnectionPool +from psycopg.rows import dict_row +from sqlalchemy.engine.url import make_url +from sqlalchemy.ext.asyncio import ( + AsyncEngine, + AsyncSession, + async_sessionmaker, + create_async_engine, +) + +from app.core.config import settings + +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class PgEngineEntry: + engine: AsyncEngine + sessionmaker: async_sessionmaker[AsyncSession] + + +@dataclass(frozen=True) +class CacheKey: + project_id: UUID + db_role: str + + +class ProjectConnectionManager: + def __init__(self) -> None: + self._pg_cache: Dict[CacheKey, PgEngineEntry] = OrderedDict() + self._ts_cache: Dict[CacheKey, AsyncConnectionPool] = OrderedDict() + self._pg_raw_cache: Dict[CacheKey, AsyncConnectionPool] = OrderedDict() + self._pg_lock = asyncio.Lock() + self._ts_lock = asyncio.Lock() + self._pg_raw_lock = asyncio.Lock() + + def _normalize_pg_url(self, url: str) -> str: + parsed = make_url(url) + if parsed.drivername == "postgresql": + parsed = parsed.set(drivername="postgresql+psycopg") + return str(parsed) + + async def get_pg_sessionmaker( + self, + project_id: UUID, + db_role: str, + connection_url: str, + pool_min_size: int, + pool_max_size: int, + ) -> async_sessionmaker[AsyncSession]: + async with self._pg_lock: + key = CacheKey(project_id=project_id, db_role=db_role) + entry = self._pg_cache.get(key) + if entry: + self._pg_cache.move_to_end(key) + return entry.sessionmaker + + normalized_url = self._normalize_pg_url(connection_url) + pool_min_size = max(1, pool_min_size) + pool_max_size = max(pool_min_size, pool_max_size) + engine = create_async_engine( + normalized_url, + pool_size=pool_min_size, + max_overflow=max(0, pool_max_size - pool_min_size), + pool_pre_ping=True, + ) + sessionmaker = async_sessionmaker(engine, expire_on_commit=False) + self._pg_cache[key] = PgEngineEntry( + engine=engine, + sessionmaker=sessionmaker, + ) + await self._evict_pg_if_needed() + logger.info( + "Created PostgreSQL engine for project %s (%s)", project_id, db_role + ) + return sessionmaker + + async def get_timescale_pool( + self, + project_id: UUID, + db_role: str, + connection_url: str, + pool_min_size: int, + pool_max_size: int, + ) -> AsyncConnectionPool: + async with self._ts_lock: + key = CacheKey(project_id=project_id, db_role=db_role) + pool = self._ts_cache.get(key) + if pool: + self._ts_cache.move_to_end(key) + return pool + + pool_min_size = max(1, pool_min_size) + pool_max_size = max(pool_min_size, pool_max_size) + pool = AsyncConnectionPool( + conninfo=connection_url, + min_size=pool_min_size, + max_size=pool_max_size, + open=False, + kwargs={"row_factory": dict_row}, + ) + await pool.open() + self._ts_cache[key] = pool + await self._evict_ts_if_needed() + logger.info( + "Created TimescaleDB pool for project %s (%s)", project_id, db_role + ) + return pool + + async def get_pg_pool( + self, + project_id: UUID, + db_role: str, + connection_url: str, + pool_min_size: int, + pool_max_size: int, + ) -> AsyncConnectionPool: + async with self._pg_raw_lock: + key = CacheKey(project_id=project_id, db_role=db_role) + pool = self._pg_raw_cache.get(key) + if pool: + self._pg_raw_cache.move_to_end(key) + return pool + + pool_min_size = max(1, pool_min_size) + pool_max_size = max(pool_min_size, pool_max_size) + pool = AsyncConnectionPool( + conninfo=connection_url, + min_size=pool_min_size, + max_size=pool_max_size, + open=False, + kwargs={"row_factory": dict_row}, + ) + await pool.open() + self._pg_raw_cache[key] = pool + await self._evict_pg_raw_if_needed() + logger.info( + "Created PostgreSQL pool for project %s (%s)", project_id, db_role + ) + return pool + + async def _evict_pg_if_needed(self) -> None: + while len(self._pg_cache) > settings.PROJECT_PG_CACHE_SIZE: + key, entry = self._pg_cache.popitem(last=False) + await entry.engine.dispose() + logger.info( + "Evicted PostgreSQL engine for project %s (%s)", + key.project_id, + key.db_role, + ) + + async def _evict_ts_if_needed(self) -> None: + while len(self._ts_cache) > settings.PROJECT_TS_CACHE_SIZE: + key, pool = self._ts_cache.popitem(last=False) + await pool.close() + logger.info( + "Evicted TimescaleDB pool for project %s (%s)", + key.project_id, + key.db_role, + ) + + async def _evict_pg_raw_if_needed(self) -> None: + while len(self._pg_raw_cache) > settings.PROJECT_PG_CACHE_SIZE: + key, pool = self._pg_raw_cache.popitem(last=False) + await pool.close() + logger.info( + "Evicted PostgreSQL pool for project %s (%s)", + key.project_id, + key.db_role, + ) + + async def close_all(self) -> None: + async with self._pg_lock: + for key, entry in list(self._pg_cache.items()): + await entry.engine.dispose() + logger.info( + "Closed PostgreSQL engine for project %s (%s)", + key.project_id, + key.db_role, + ) + self._pg_cache.clear() + + async with self._ts_lock: + for key, pool in list(self._ts_cache.items()): + await pool.close() + logger.info( + "Closed TimescaleDB pool for project %s (%s)", + key.project_id, + key.db_role, + ) + self._ts_cache.clear() + + async with self._pg_raw_lock: + for key, pool in list(self._pg_raw_cache.items()): + await pool.close() + logger.info( + "Closed PostgreSQL pool for project %s (%s)", + key.project_id, + key.db_role, + ) + self._pg_raw_cache.clear() + + +project_connection_manager = ProjectConnectionManager() diff --git a/app/infra/db/influxdb/__init__.py b/app/infra/db/influxdb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/influxdb_api.py b/app/infra/db/influxdb/api.py similarity index 97% rename from influxdb_api.py rename to app/infra/db/influxdb/api.py index b9afd39..9aa20b0 100644 --- a/influxdb_api.py +++ b/app/infra/db/influxdb/api.py @@ -13,23 +13,23 @@ from typing import List, Dict from datetime import datetime, timedelta, timezone from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS from dateutil import parser -import get_realValue -import get_data +# import get_realValue +# import get_data import psycopg import time -import simulation -from tjnetwork import * +import app.services.simulation as simulation +from app.services.tjnetwork import close_project, get_time, is_project_open, open_project import schedule import threading -import globals +import app.services.globals as globals import csv import pandas as pd import openpyxl import pytz -import influxdb_info -import project_info -import time_api -from api.postgresql_info import get_pgconn_string +import app.infra.db.influxdb.info as influxdb_info +import app.services.project_info as project_info +import app.services.time_api as time_api +from app.core.config import get_pgconn_string # influxdb数据库连接信息 url = influxdb_info.url @@ -404,8 +404,8 @@ def create_and_initialize_buckets(org_name: str) -> None: Point("link") .tag("date", None) .tag("ID", None) - .tag("scheme_Type", None) - .tag("scheme_Name", None) + .tag("scheme_type", None) + .tag("scheme_name", None) .field("flow", 0.0) .field("leakage", 0.0) .field("velocity", 0.0) @@ -420,8 +420,8 @@ def create_and_initialize_buckets(org_name: str) -> None: Point("node") .tag("date", None) .tag("ID", None) - .tag("scheme_Type", None) - .tag("scheme_Name", None) + .tag("scheme_type", None) + .tag("scheme_name", None) .field("head", 0.0) .field("pressure", 0.0) .field("actualdemand", 0.0) @@ -436,8 +436,8 @@ def create_and_initialize_buckets(org_name: str) -> None: .tag("date", None) .tag("description", None) .tag("device_ID", None) - .tag("scheme_Type", None) - .tag("scheme_Name", None) + .tag("scheme_type", None) + .tag("scheme_name", None) .field("monitored_value", 0.0) .field("datacleaning_value", 0.0) .field("scheme_simulation_value", 0.0) @@ -1811,8 +1811,8 @@ def query_SCADA_data_by_device_ID_and_time( def query_scheme_SCADA_data_by_device_ID_and_time( query_ids_list: List[str], query_time: str, - scheme_Type: str, - scheme_Name: str, + scheme_type: str, + scheme_name: str, bucket: str = "scheme_simulation_result", ) -> Dict[str, float]: """ @@ -1843,7 +1843,7 @@ def query_scheme_SCADA_data_by_device_ID_and_time( flux_query = f""" from(bucket: "{bucket}") |> range(start: {utc_start_time.isoformat()}, stop: {utc_stop_time.isoformat()}) - |> filter(fn: (r) => r["device_ID"] == "{device_id}" and r["_field"] == "monitored_value" and r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}") + |> filter(fn: (r) => r["device_ID"] == "{device_id}" and r["_field"] == "monitored_value" and r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}") """ # 执行查询 try: @@ -2585,7 +2585,7 @@ def query_all_scheme_record_by_time_property( flux_query = f""" from(bucket: "{bucket}") |> range(start: {utc_start_time.isoformat()}, stop: {utc_stop_time.isoformat()}) - |> filter(fn: (r) => r["scheme_Name"] == "{scheme_name}" and r["_measurement"] == "{measurement}" and r["_field"] == "{property}") + |> filter(fn: (r) => r["scheme_name"] == "{scheme_name}" and r["_measurement"] == "{measurement}" and r["_field"] == "{property}") """ # 执行查询 tables = query_api.query(flux_query) @@ -2635,7 +2635,7 @@ def query_scheme_simulation_result_by_ID_time( flux_query = f""" from(bucket: "{bucket}") |> range(start: {utc_start_time.isoformat()}, stop: {utc_stop_time.isoformat()}) - |> filter(fn: (r) => r["scheme_Name"] == "{scheme_name}" and r["_measurement"] == "node" and r["ID"] == "{ID}") + |> filter(fn: (r) => r["scheme_name"] == "{scheme_name}" and r["_measurement"] == "node" and r["ID"] == "{ID}") |> pivot( rowKey:["_time"], columnKey:["_field"], @@ -2660,7 +2660,7 @@ def query_scheme_simulation_result_by_ID_time( flux_query = f""" from(bucket: "{bucket}") |> range(start: {utc_start_time.isoformat()}, stop: {utc_stop_time.isoformat()}) - |> filter(fn: (r) => r["scheme_Name"] == "{scheme_name}" and r["_measurement"] == "link" and r["ID"] == "{ID}") + |> filter(fn: (r) => r["scheme_name"] == "{scheme_name}" and r["_measurement"] == "link" and r["ID"] == "{ID}") |> pivot( rowKey:["_time"], columnKey:["_field"], @@ -3227,8 +3227,8 @@ def store_scheme_simulation_result_to_influxdb( link_result_list: List[Dict[str, any]], scheme_start_time: str, num_periods: int = 1, - scheme_Type: str = None, - scheme_Name: str = None, + scheme_type: str = None, + scheme_name: str = None, bucket: str = "scheme_simulation_result", ): """ @@ -3237,8 +3237,8 @@ def store_scheme_simulation_result_to_influxdb( :param link_result_list: (List[Dict[str, any]]): 包含连接和结果数据的字典列表。 :param scheme_start_time: (str): 方案模拟开始时间。 :param num_periods: (int): 方案模拟的周期数 - :param scheme_Type: (str): 方案类型 - :param scheme_Name: (str): 方案名称 + :param scheme_type: (str): 方案类型 + :param scheme_name: (str): 方案名称 :param bucket: (str): InfluxDB 的 bucket 名称,默认值为 "scheme_simulation_result"。 :return: """ @@ -3298,8 +3298,8 @@ def store_scheme_simulation_result_to_influxdb( Point("node") .tag("date", date_str) .tag("ID", node_id) - .tag("scheme_Type", scheme_Type) - .tag("scheme_Name", scheme_Name) + .tag("scheme_type", scheme_type) + .tag("scheme_name", scheme_name) .field("head", data.get("head", 0.0)) .field("pressure", data.get("pressure", 0.0)) .field("actualdemand", data.get("demand", 0.0)) @@ -3322,8 +3322,8 @@ def store_scheme_simulation_result_to_influxdb( Point("link") .tag("date", date_str) .tag("ID", link_id) - .tag("scheme_Type", scheme_Type) - .tag("scheme_Name", scheme_Name) + .tag("scheme_type", scheme_type) + .tag("scheme_name", scheme_name) .field("flow", data.get("flow", 0.0)) .field("velocity", data.get("velocity", 0.0)) .field("headloss", data.get("headloss", 0.0)) @@ -3409,14 +3409,14 @@ def query_corresponding_query_id_and_element_id(name: str) -> None: # 2025/03/11 def fill_scheme_simulation_result_to_SCADA( - scheme_Type: str = None, - scheme_Name: str = None, + scheme_type: str = None, + scheme_name: str = None, query_date: str = None, bucket: str = "scheme_simulation_result", ): """ - :param scheme_Type: 方案类型 - :param scheme_Name: 方案名称 + :param scheme_type: 方案类型 + :param scheme_name: 方案名称 :param query_date: 查询日期,格式为 'YYYY-MM-DD' :param bucket: InfluxDB 的 bucket 名称,默认值为 "scheme_simulation_result" :return: @@ -3457,8 +3457,8 @@ def fill_scheme_simulation_result_to_SCADA( # 查找associated_element_id的对应值 for key, value in globals.scheme_source_outflow_ids.items(): scheme_source_outflow_result = query_scheme_curve_by_ID_property( - scheme_Type=scheme_Type, - scheme_Name=scheme_Name, + scheme_type=scheme_type, + scheme_name=scheme_name, query_date=query_date, ID=value, type="link", @@ -3470,8 +3470,8 @@ def fill_scheme_simulation_result_to_SCADA( Point("scheme_source_outflow") .tag("date", query_date) .tag("device_ID", key) - .tag("scheme_Type", scheme_Type) - .tag("scheme_Name", scheme_Name) + .tag("scheme_type", scheme_type) + .tag("scheme_name", scheme_name) .field("monitored_value", data["value"]) .time(data["time"], write_precision="s") ) @@ -3480,8 +3480,8 @@ def fill_scheme_simulation_result_to_SCADA( for key, value in globals.scheme_pipe_flow_ids.items(): scheme_pipe_flow_result = query_scheme_curve_by_ID_property( - scheme_Type=scheme_Type, - scheme_Name=scheme_Name, + scheme_type=scheme_type, + scheme_name=scheme_name, query_date=query_date, ID=value, type="link", @@ -3492,8 +3492,8 @@ def fill_scheme_simulation_result_to_SCADA( Point("scheme_pipe_flow") .tag("date", query_date) .tag("device_ID", key) - .tag("scheme_Type", scheme_Type) - .tag("scheme_Name", scheme_Name) + .tag("scheme_type", scheme_type) + .tag("scheme_name", scheme_name) .field("monitored_value", data["value"]) .time(data["time"], write_precision="s") ) @@ -3502,8 +3502,8 @@ def fill_scheme_simulation_result_to_SCADA( for key, value in globals.scheme_pressure_ids.items(): scheme_pressure_result = query_scheme_curve_by_ID_property( - scheme_Type=scheme_Type, - scheme_Name=scheme_Name, + scheme_type=scheme_type, + scheme_name=scheme_name, query_date=query_date, ID=value, type="node", @@ -3514,8 +3514,8 @@ def fill_scheme_simulation_result_to_SCADA( Point("scheme_pressure") .tag("date", query_date) .tag("device_ID", key) - .tag("scheme_Type", scheme_Type) - .tag("scheme_Name", scheme_Name) + .tag("scheme_type", scheme_type) + .tag("scheme_name", scheme_name) .field("monitored_value", data["value"]) .time(data["time"], write_precision="s") ) @@ -3524,8 +3524,8 @@ def fill_scheme_simulation_result_to_SCADA( for key, value in globals.scheme_demand_ids.items(): scheme_demand_result = query_scheme_curve_by_ID_property( - scheme_Type=scheme_Type, - scheme_Name=scheme_Name, + scheme_type=scheme_type, + scheme_name=scheme_name, query_date=query_date, ID=value, type="node", @@ -3536,8 +3536,8 @@ def fill_scheme_simulation_result_to_SCADA( Point("scheme_demand") .tag("date", query_date) .tag("device_ID", key) - .tag("scheme_Type", scheme_Type) - .tag("scheme_Name", scheme_Name) + .tag("scheme_type", scheme_type) + .tag("scheme_name", scheme_name) .field("monitored_value", data["value"]) .time(data["time"], write_precision="s") ) @@ -3546,8 +3546,8 @@ def fill_scheme_simulation_result_to_SCADA( for key, value in globals.scheme_quality_ids.items(): scheme_quality_result = query_scheme_curve_by_ID_property( - scheme_Type=scheme_Type, - scheme_Name=scheme_Name, + scheme_type=scheme_type, + scheme_name=scheme_name, query_date=query_date, ID=value, type="node", @@ -3558,8 +3558,8 @@ def fill_scheme_simulation_result_to_SCADA( Point("scheme_quality") .tag("date", query_date) .tag("device_ID", key) - .tag("scheme_Type", scheme_Type) - .tag("scheme_Name", scheme_Name) + .tag("scheme_type", scheme_type) + .tag("scheme_name", scheme_name) .field("monitored_value", data["value"]) .time(data["time"], write_precision="s") ) @@ -3629,15 +3629,15 @@ def query_SCADA_data_curve( # 2025/02/18 def query_scheme_all_record_by_time( - scheme_Type: str, - scheme_Name: str, + scheme_type: str, + scheme_name: str, query_time: str, bucket: str = "scheme_simulation_result", ) -> tuple: """ 查询指定方案某一时刻的所有记录,包括‘node'和‘link’,分别以指定格式返回。 - :param scheme_Type: 方案类型 - :param scheme_Name: 方案名称 + :param scheme_type: 方案类型 + :param scheme_name: 方案名称 :param query_time: 输入的北京时间,格式为 '2024-11-24T17:30:00+08:00'。 :param bucket: 数据存储的 bucket 名称。 :return: dict: tuple: (node_records, link_records) @@ -3660,7 +3660,7 @@ def query_scheme_all_record_by_time( flux_query = f""" from(bucket: "{bucket}") |> range(start: {utc_start_time.isoformat()}, stop: {utc_stop_time.isoformat()}) - |> filter(fn: (r) => r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}" and r["_measurement"] == "node" or r["_measurement"] == "link") + |> filter(fn: (r) => r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}" and r["_measurement"] == "node" or r["_measurement"] == "link") |> pivot( rowKey:["_time"], columnKey:["_field"], @@ -3710,8 +3710,8 @@ def query_scheme_all_record_by_time( # 2025/03/04 def query_scheme_all_record_by_time_property( - scheme_Type: str, - scheme_Name: str, + scheme_type: str, + scheme_name: str, query_time: str, type: str, property: str, @@ -3719,8 +3719,8 @@ def query_scheme_all_record_by_time_property( ) -> list: """ 查询指定方案某一时刻‘node'或‘link’某一属性值,以指定格式返回。 - :param scheme_Type: 方案类型 - :param scheme_Name: 方案名称 + :param scheme_type: 方案类型 + :param scheme_name: 方案名称 :param query_time: 输入的北京时间,格式为 '2024-11-24T17:30:00+08:00'。 :param type: 查询的类型(决定 measurement) :param property: 查询的字段名称(field) @@ -3752,7 +3752,7 @@ def query_scheme_all_record_by_time_property( flux_query = f""" from(bucket: "{bucket}") |> range(start: {utc_start_time.isoformat()}, stop: {utc_stop_time.isoformat()}) - |> filter(fn: (r) => r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}" and r["_measurement"] == "{measurement}" and r["_field"] == "{property}") + |> filter(fn: (r) => r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}" and r["_measurement"] == "{measurement}" and r["_field"] == "{property}") """ # 执行查询 tables = query_api.query(flux_query) @@ -3767,8 +3767,8 @@ def query_scheme_all_record_by_time_property( # 2025/02/19 def query_scheme_curve_by_ID_property( - scheme_Type: str, - scheme_Name: str, + scheme_type: str, + scheme_name: str, query_date: str, ID: str, type: str, @@ -3776,9 +3776,9 @@ def query_scheme_curve_by_ID_property( bucket: str = "scheme_simulation_result", ) -> list: """ - 根据scheme_Type和scheme_Name,查询该模拟方案中,某一node或link的某一属性值的所有时间的结果 - :param scheme_Type: 方案类型 - :param scheme_Name: 方案名称 + 根据scheme_Type和scheme_name,查询该模拟方案中,某一node或link的某一属性值的所有时间的结果 + :param scheme_type: 方案类型 + :param scheme_name: 方案名称 :param query_date: 查询日期,格式为 'YYYY-MM-DD' :param ID: 元素的ID :param type: 元素的类型,node或link @@ -3817,7 +3817,7 @@ def query_scheme_curve_by_ID_property( flux_query = f""" from(bucket: "{bucket}") |> range(start: {start_time}, stop: {stop_time}) - |> filter(fn: (r) => r["_measurement"] == "{measurement}" and r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}" and r["ID"] == "{ID}" and r["_field"] == "{property}") + |> filter(fn: (r) => r["_measurement"] == "{measurement}" and r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}" and r["ID"] == "{ID}" and r["_field"] == "{property}") """ # 执行查询 tables = query_api.query(flux_query) @@ -3832,15 +3832,15 @@ def query_scheme_curve_by_ID_property( # 2025/02/21 def query_scheme_all_record( - scheme_Type: str, - scheme_Name: str, + scheme_type: str, + scheme_name: str, query_date: str, bucket: str = "scheme_simulation_result", ) -> tuple: """ 查询指定方案的所有记录,包括‘node'和‘link’,分别以指定格式返回。 - :param scheme_Type: 方案类型 - :param scheme_Name: 方案名称 + :param scheme_type: 方案类型 + :param scheme_name: 方案名称 :param query_date: 查询日期,格式为 'YYYY-MM-DD' :param bucket: 数据存储的 bucket 名称。 :return: dict: tuple: (node_records, link_records) @@ -3867,7 +3867,7 @@ def query_scheme_all_record( flux_query = f""" from(bucket: "{bucket}") |> range(start: {utc_start_time.isoformat()}, stop: {utc_stop_time.isoformat()}) - |> filter(fn: (r) => r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}" and r["_measurement"] == "node" or r["_measurement"] == "link") + |> filter(fn: (r) => r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}" and r["_measurement"] == "node" or r["_measurement"] == "link") |> pivot( rowKey:["_time"], columnKey:["_field"], @@ -3917,8 +3917,8 @@ def query_scheme_all_record( # 2025/03/04 def query_scheme_all_record_property( - scheme_Type: str, - scheme_Name: str, + scheme_type: str, + scheme_name: str, query_date: str, type: str, property: str, @@ -3926,8 +3926,8 @@ def query_scheme_all_record_property( ) -> list: """ 查询指定方案的‘node'或‘link’的某一属性值,以指定格式返回。 - :param scheme_Type: 方案类型 - :param scheme_Name: 方案名称 + :param scheme_type: 方案类型 + :param scheme_name: 方案名称 :param query_date: 查询日期,格式为 'YYYY-MM-DD' :param type: 查询的类型(决定 measurement) :param property: 查询的字段名称(field) @@ -3964,7 +3964,7 @@ def query_scheme_all_record_property( flux_query = f""" from(bucket: "{bucket}") |> range(start: {start_time}, stop: {stop_time}) - |> filter(fn: (r) => r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}" and r["date"] == "{query_date}" and r["_measurement"] == "{measurement}" and r["_field"] == "{property}") + |> filter(fn: (r) => r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}" and r["date"] == "{query_date}" and r["_measurement"] == "{measurement}" and r["_field"] == "{property}") """ # 执行查询 tables = query_api.query(flux_query) @@ -4245,8 +4245,8 @@ def export_scheme_simulation_result_to_csv_time( link_data[key][field] = record.get_value() link_data[key]["measurement"] = record.get_measurement() link_data[key]["date"] = record.values.get("date", None) - link_data[key]["scheme_Type"] = record.values.get("scheme_Type", None) - link_data[key]["scheme_Name"] = record.values.get("scheme_Name", None) + link_data[key]["scheme_type"] = record.values.get("scheme_type", None) + link_data[key]["scheme_name"] = record.values.get("scheme_name", None) # 构建 Flux 查询语句,查询指定时间范围内的数据 flux_query_node = f""" from(bucket: "{bucket}") @@ -4267,8 +4267,8 @@ def export_scheme_simulation_result_to_csv_time( node_data[key][field] = record.get_value() node_data[key]["measurement"] = record.get_measurement() node_data[key]["date"] = record.values.get("date", None) - node_data[key]["scheme_Type"] = record.values.get("scheme_Type", None) - node_data[key]["scheme_Name"] = record.values.get("scheme_Name", None) + node_data[key]["scheme_type"] = record.values.get("scheme_type", None) + node_data[key]["scheme_name"] = record.values.get("scheme_name", None) for key in set(link_data.keys()): row = {"time": key[0], "ID": key[1]} row.update(link_data.get(key, {})) @@ -4288,8 +4288,8 @@ def export_scheme_simulation_result_to_csv_time( "time", "measurement", "date", - "scheme_Type", - "scheme_Name", + "scheme_type", + "scheme_name", "ID", "flow", "leakage", @@ -4311,8 +4311,8 @@ def export_scheme_simulation_result_to_csv_time( "time", "measurement", "date", - "scheme_Type", - "scheme_Name", + "scheme_type", + "scheme_name", "ID", "head", "pressure", @@ -4330,15 +4330,15 @@ def export_scheme_simulation_result_to_csv_time( # 2025/02/18 def export_scheme_simulation_result_to_csv_scheme( - scheme_Type: str, - scheme_Name: str, + scheme_type: str, + scheme_name: str, query_date: str, bucket: str = "scheme_simulation_result", ) -> None: """ 导出influxdb中scheme_simulation_result这个bucket的数据到csv中 - :param scheme_Type: 查询的方案类型 - :param scheme_Name: 查询的方案名 + :param scheme_type: 查询的方案类型 + :param scheme_name: 查询的方案名 :param query_date: 查询日期,格式为 'YYYY-MM-DD' :param bucket: 数据存储的 bucket 名称,默认值为 "SCADA_data" :return: @@ -4366,7 +4366,7 @@ def export_scheme_simulation_result_to_csv_scheme( flux_query_link = f""" from(bucket: "{bucket}") |> range(start: {start_time}, stop: {stop_time}) - |> filter(fn: (r) => r["_measurement"] == "link" and r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}") + |> filter(fn: (r) => r["_measurement"] == "link" and r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}") """ # 执行查询 link_tables = query_api.query(flux_query_link) @@ -4382,13 +4382,13 @@ def export_scheme_simulation_result_to_csv_scheme( link_data[key][field] = record.get_value() link_data[key]["measurement"] = record.get_measurement() link_data[key]["date"] = record.values.get("date", None) - link_data[key]["scheme_Type"] = record.values.get("scheme_Type", None) - link_data[key]["scheme_Name"] = record.values.get("scheme_Name", None) + link_data[key]["scheme_type"] = record.values.get("scheme_type", None) + link_data[key]["scheme_name"] = record.values.get("scheme_name", None) # 构建 Flux 查询语句,查询指定时间范围内的数据 flux_query_node = f""" from(bucket: "{bucket}") |> range(start: {start_time}, stop: {stop_time}) - |> filter(fn: (r) => r["_measurement"] == "node" and r["scheme_Type"] == "{scheme_Type}" and r["scheme_Name"] == "{scheme_Name}") + |> filter(fn: (r) => r["_measurement"] == "node" and r["scheme_type"] == "{scheme_type}" and r["scheme_name"] == "{scheme_name}") """ # 执行查询 node_tables = query_api.query(flux_query_node) @@ -4404,8 +4404,8 @@ def export_scheme_simulation_result_to_csv_scheme( node_data[key][field] = record.get_value() node_data[key]["measurement"] = record.get_measurement() node_data[key]["date"] = record.values.get("date", None) - node_data[key]["scheme_Type"] = record.values.get("scheme_Type", None) - node_data[key]["scheme_Name"] = record.values.get("scheme_Name", None) + node_data[key]["scheme_type"] = record.values.get("scheme_type", None) + node_data[key]["scheme_name"] = record.values.get("scheme_name", None) for key in set(link_data.keys()): row = {"time": key[0], "ID": key[1]} row.update(link_data.get(key, {})) @@ -4416,10 +4416,10 @@ def export_scheme_simulation_result_to_csv_scheme( node_rows.append(row) # 动态生成 CSV 文件名 csv_filename_link = ( - f"scheme_simulation_link_result_{scheme_Name}_of_{scheme_Type}.csv" + f"scheme_simulation_link_result_{scheme_name}_of_{scheme_type}.csv" ) csv_filename_node = ( - f"scheme_simulation_node_result_{scheme_Name}_of_{scheme_Type}.csv" + f"scheme_simulation_node_result_{scheme_name}_of_{scheme_type}.csv" ) # 写入到 CSV 文件 with open(csv_filename_link, mode="w", newline="") as file: @@ -4429,8 +4429,8 @@ def export_scheme_simulation_result_to_csv_scheme( "time", "measurement", "date", - "scheme_Type", - "scheme_Name", + "scheme_type", + "scheme_name", "ID", "flow", "leakage", @@ -4452,8 +4452,8 @@ def export_scheme_simulation_result_to_csv_scheme( "time", "measurement", "date", - "scheme_Type", - "scheme_Name", + "scheme_type", + "scheme_name", "ID", "head", "pressure", @@ -4878,15 +4878,15 @@ if __name__ == "__main__": # export_scheme_simulation_result_to_csv_time(start_date='2025-02-13', end_date='2025-02-15') # 示例9:export_scheme_simulation_result_to_csv_scheme - # export_scheme_simulation_result_to_csv_scheme(scheme_Type='burst_Analysis', scheme_Name='scheme1', query_date='2025-03-10') + # export_scheme_simulation_result_to_csv_scheme(scheme_type='burst_Analysis', scheme_name='scheme1', query_date='2025-03-10') # 示例10:query_scheme_all_record_by_time - # node_records, link_records = query_scheme_all_record_by_time(scheme_Type='burst_Analysis', scheme_Name='scheme1', query_time="2025-02-14T10:30:00+08:00") + # node_records, link_records = query_scheme_all_record_by_time(scheme_type='burst_Analysis', scheme_name='scheme1', query_time="2025-02-14T10:30:00+08:00") # print("Node 数据:", node_records) # print("Link 数据:", link_records) # 示例11:query_scheme_curve_by_ID_property - # curve_result = query_scheme_curve_by_ID_property(scheme_Type='burst_Analysis', scheme_Name='scheme1', ID='ZBBDTZDP000022', + # curve_result = query_scheme_curve_by_ID_property(scheme_type='burst_Analysis', scheme_name='scheme1', ID='ZBBDTZDP000022', # type='node', property='head') # print(curve_result) @@ -4896,7 +4896,7 @@ if __name__ == "__main__": # print("Link 数据:", link_records) # 示例13:query_scheme_all_record - # node_records, link_records = query_scheme_all_record(scheme_Type='burst_Analysis', scheme_Name='scheme1', query_date='2025-03-10') + # node_records, link_records = query_scheme_all_record(scheme_type='burst_Analysis', scheme_name='scheme1', query_date='2025-03-10') # print("Node 数据:", node_records) # print("Link 数据:", link_records) @@ -4909,16 +4909,16 @@ if __name__ == "__main__": # print(result_records) # 示例16:query_scheme_all_record_by_time_property - # result_records = query_scheme_all_record_by_time_property(scheme_Type='burst_Analysis', scheme_Name='scheme1', + # result_records = query_scheme_all_record_by_time_property(scheme_type='burst_Analysis', scheme_name='scheme1', # query_time='2025-02-14T10:30:00+08:00', type='node', property='head') # print(result_records) # 示例17:query_scheme_all_record_property - # result_records = query_scheme_all_record_property(scheme_Type='burst_Analysis', scheme_Name='scheme1', query_date='2025-03-10', type='node', property='head') + # result_records = query_scheme_all_record_property(scheme_type='burst_Analysis', scheme_name='scheme1', query_date='2025-03-10', type='node', property='head') # print(result_records) # 示例18:fill_scheme_simulation_result_to_SCADA - # fill_scheme_simulation_result_to_SCADA(scheme_Type='burst_Analysis', scheme_Name='burst0330', query_date='2025-03-30') + # fill_scheme_simulation_result_to_SCADA(scheme_type='burst_Analysis', scheme_name='burst0330', query_date='2025-03-30') # 示例19:query_SCADA_data_by_device_ID_and_timerange # result = query_SCADA_data_by_device_ID_and_timerange(query_ids_list=globals.pressure_non_realtime_ids, start_time='2025-04-16T00:00:00+08:00', @@ -4926,7 +4926,7 @@ if __name__ == "__main__": # print(result) # 示例:manually_get_burst_flow - # leakage = manually_get_burst_flow(scheme_Type='burst_Analysis', scheme_Name='burst_scheme', scheme_start_time='2025-03-10T12:00:00+08:00') + # leakage = manually_get_burst_flow(scheme_type='burst_Analysis', scheme_name='burst_scheme', scheme_start_time='2025-03-10T12:00:00+08:00') # print(leakage) # 示例:upload_cleaned_SCADA_data_to_influxdb diff --git a/influxdb_info.py b/app/infra/db/influxdb/info.py similarity index 100% rename from influxdb_info.py rename to app/infra/db/influxdb/info.py diff --git a/influxdb_query_SCADA_data.py b/app/infra/db/influxdb/query.py similarity index 100% rename from influxdb_query_SCADA_data.py rename to app/infra/db/influxdb/query.py diff --git a/app/infra/db/metadata/__init__.py b/app/infra/db/metadata/__init__.py new file mode 100644 index 0000000..9db5443 --- /dev/null +++ b/app/infra/db/metadata/__init__.py @@ -0,0 +1,3 @@ +from .database import get_metadata_session, close_metadata_engine + +__all__ = ["get_metadata_session", "close_metadata_engine"] diff --git a/app/infra/db/metadata/database.py b/app/infra/db/metadata/database.py new file mode 100644 index 0000000..52adfd2 --- /dev/null +++ b/app/infra/db/metadata/database.py @@ -0,0 +1,27 @@ +import logging +from typing import AsyncGenerator + +from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine + +from app.core.config import settings + +logger = logging.getLogger(__name__) + +engine = create_async_engine( + settings.METADATA_DATABASE_URI, + pool_size=settings.METADATA_DB_POOL_SIZE, + max_overflow=settings.METADATA_DB_MAX_OVERFLOW, + pool_pre_ping=True, +) + +SessionLocal = async_sessionmaker(engine, expire_on_commit=False) + + +async def get_metadata_session() -> AsyncGenerator[AsyncSession, None]: + async with SessionLocal() as session: + yield session + + +async def close_metadata_engine() -> None: + await engine.dispose() + logger.info("Metadata database engine disposed.") diff --git a/app/infra/db/metadata/models.py b/app/infra/db/metadata/models.py new file mode 100644 index 0000000..7c48643 --- /dev/null +++ b/app/infra/db/metadata/models.py @@ -0,0 +1,117 @@ +from datetime import datetime +from uuid import UUID, uuid4 + +from sqlalchemy import Boolean, DateTime, Integer, String, Text +from sqlalchemy.dialects.postgresql import JSONB, UUID as PGUUID +from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column + + +class Base(DeclarativeBase): + pass + + +class User(Base): + __tablename__ = "users" + + id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) + keycloak_id: Mapped[UUID] = mapped_column( + PGUUID(as_uuid=True), unique=True, index=True + ) + username: Mapped[str] = mapped_column(String(50), unique=True) + email: Mapped[str] = mapped_column(String(100), unique=True) + role: Mapped[str] = mapped_column(String(20), default="user") + is_active: Mapped[bool] = mapped_column(Boolean, default=True) + is_superuser: Mapped[bool] = mapped_column(Boolean, default=False) + attributes: Mapped[dict | None] = mapped_column(JSONB, nullable=True) + created_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=datetime.utcnow + ) + updated_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=datetime.utcnow + ) + last_login_at: Mapped[datetime | None] = mapped_column( + DateTime(timezone=True), nullable=True + ) + + +class Project(Base): + __tablename__ = "projects" + + id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) + name: Mapped[str] = mapped_column(String(100)) + code: Mapped[str] = mapped_column(String(50), unique=True) + description: Mapped[str | None] = mapped_column(Text, nullable=True) + gs_workspace: Mapped[str] = mapped_column(String(100), unique=True) + status: Mapped[str] = mapped_column(String(20), default="active") + created_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=datetime.utcnow + ) + updated_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=datetime.utcnow + ) + + +class ProjectDatabase(Base): + __tablename__ = "project_databases" + + id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) + project_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), index=True) + db_role: Mapped[str] = mapped_column(String(20)) + db_type: Mapped[str] = mapped_column(String(20)) + dsn_encrypted: Mapped[str] = mapped_column(Text) + pool_min_size: Mapped[int] = mapped_column(Integer, default=2) + pool_max_size: Mapped[int] = mapped_column(Integer, default=10) + + +class ProjectGeoServerConfig(Base): + __tablename__ = "project_geoserver_configs" + + id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) + project_id: Mapped[UUID] = mapped_column( + PGUUID(as_uuid=True), unique=True, index=True + ) + gs_base_url: Mapped[str | None] = mapped_column(Text, nullable=True) + gs_admin_user: Mapped[str | None] = mapped_column(String(50), nullable=True) + gs_admin_password_encrypted: Mapped[str | None] = mapped_column( + Text, nullable=True + ) + gs_datastore_name: Mapped[str] = mapped_column(String(100), default="ds_postgis") + default_extent: Mapped[dict | None] = mapped_column(JSONB, nullable=True) + srid: Mapped[int] = mapped_column(Integer, default=4326) + updated_at: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=datetime.utcnow + ) + + +class UserProjectMembership(Base): + __tablename__ = "user_project_membership" + + id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True) + user_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), index=True) + project_id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), index=True) + project_role: Mapped[str] = mapped_column(String(20), default="viewer") + + +class AuditLog(Base): + __tablename__ = "audit_logs" + + id: Mapped[UUID] = mapped_column( + PGUUID(as_uuid=True), primary_key=True, default=uuid4 + ) + user_id: Mapped[UUID | None] = mapped_column( + PGUUID(as_uuid=True), nullable=True, index=True + ) + project_id: Mapped[UUID | None] = mapped_column( + PGUUID(as_uuid=True), nullable=True, index=True + ) + action: Mapped[str] = mapped_column(String(50)) + resource_type: Mapped[str | None] = mapped_column(String(50), nullable=True) + resource_id: Mapped[str | None] = mapped_column(String(100), nullable=True) + ip_address: Mapped[str | None] = mapped_column(String(45), nullable=True) + request_method: Mapped[str | None] = mapped_column(String(10), nullable=True) + request_path: Mapped[str | None] = mapped_column(Text, nullable=True) + request_data: Mapped[dict | None] = mapped_column(JSONB, nullable=True) + response_status: Mapped[int | None] = mapped_column(Integer, nullable=True) + timestamp: Mapped[datetime] = mapped_column( + DateTime(timezone=True), default=datetime.utcnow + ) diff --git a/app/infra/db/postgresql/__init__.py b/app/infra/db/postgresql/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/infra/db/postgresql/__init__.py @@ -0,0 +1 @@ + diff --git a/app/infra/db/postgresql/database.py b/app/infra/db/postgresql/database.py new file mode 100644 index 0000000..938db68 --- /dev/null +++ b/app/infra/db/postgresql/database.py @@ -0,0 +1,115 @@ +import logging +from contextlib import asynccontextmanager +from typing import AsyncGenerator, Dict, Optional +import psycopg_pool +from psycopg.rows import dict_row +import app.core.config as postgresql_info + +# Configure logging +logger = logging.getLogger(__name__) + + +class Database: + def __init__(self, db_name=None): + self.pool = None + self.db_name = db_name + + def init_pool(self, db_name=None): + """Initialize the connection pool.""" + # Use provided db_name, or the one from constructor, or default from config + target_db_name = db_name or self.db_name + + # Get connection string, handling default case where target_db_name might be None + if target_db_name: + conn_string = postgresql_info.get_pgconn_string(db_name=target_db_name) + else: + conn_string = postgresql_info.get_pgconn_string() + + try: + self.pool = psycopg_pool.AsyncConnectionPool( + conninfo=conn_string, + min_size=5, + max_size=20, + open=False, # Don't open immediately, wait for startup + kwargs={"row_factory": dict_row}, # Return rows as dictionaries + ) + logger.info(f"PostgreSQL connection pool initialized for database: {target_db_name or 'default'}") + except Exception as e: + logger.error(f"Failed to initialize postgresql connection pool: {e}") + raise + + async def open(self): + if self.pool: + await self.pool.open() + + async def close(self): + """Close the connection pool.""" + if self.pool: + await self.pool.close() + logger.info("PostgreSQL connection pool closed.") + + @asynccontextmanager + async def get_connection(self) -> AsyncGenerator: + """Get a connection from the pool.""" + if not self.pool: + raise Exception("Database pool is not initialized.") + + async with self.pool.connection() as conn: + yield conn + + +# 默认数据库实例 +db = Database() + +# 缓存不同数据库的实例 - 避免重复创建连接池 +_database_instances: Dict[str, Database] = {} + + +def create_database_instance(db_name): + """Create a new Database instance for a specific database.""" + return Database(db_name=db_name) + + +async def get_database_instance(db_name: Optional[str] = None) -> Database: + """Get or create a database instance for the specified database name.""" + if not db_name: + return db # 返回默认数据库实例 + + if db_name not in _database_instances: + # 创建新的数据库实例 + instance = create_database_instance(db_name) + instance.init_pool() + await instance.open() + _database_instances[db_name] = instance + logger.info(f"Created new database instance for: {db_name}") + + return _database_instances[db_name] + + +async def get_db_connection(): + """Dependency for FastAPI to get a database connection.""" + async with db.get_connection() as conn: + yield conn + + +async def get_database_connection(db_name: Optional[str] = None): + """ + FastAPI dependency to get database connection with optional database name. + 使用方法: conn: AsyncConnection = Depends(lambda: get_database_connection("your_db_name")) + 或在路由函数中: conn: AsyncConnection = Depends(get_database_connection) + """ + instance = await get_database_instance(db_name) + async with instance.get_connection() as conn: + yield conn + + +async def cleanup_database_instances(): + """Clean up all database instances (call this on application shutdown).""" + for db_name, instance in _database_instances.items(): + await instance.close() + logger.info(f"Closed database instance for: {db_name}") + _database_instances.clear() + + # 关闭默认数据库 + await db.close() + logger.info("All database instances cleaned up.") diff --git a/app/infra/db/postgresql/internal_queries.py b/app/infra/db/postgresql/internal_queries.py new file mode 100644 index 0000000..07cc254 --- /dev/null +++ b/app/infra/db/postgresql/internal_queries.py @@ -0,0 +1,83 @@ +import time +from typing import List, Optional + +from fastapi.logger import logger +import app.core.config as postgresql_info +import psycopg + + +class InternalQueries: + @staticmethod + def get_links_by_property( + fields: Optional[List[str]] = None, + property_conditions: Optional[dict] = None, + db_name: str = None, + max_retries: int = 3, + ) -> List[dict]: + """ + 查询pg数据库中,pipes 的指定字段记录或根据属性筛选 + :param fields: 要查询的字段列表,如 ["id", "diameter", "status"],默认查询所有字段 + :param property: 可选的筛选条件字典,如 {"status": "Open"} 或 {"diameter": 300} + :param db_name: 数据库名称 + :param max_retries: 最大重试次数 + :return: 包含所有记录的列表,每条记录为一个字典 + """ + # 如果未指定字段,查询所有字段 + if not fields: + fields = [ + "id", + "node1", + "node2", + "length", + "diameter", + "roughness", + "minor_loss", + "status", + ] + + for attempt in range(max_retries): + try: + conn_string = ( + postgresql_info.get_pgconn_string(db_name=db_name) + if db_name + else postgresql_info.get_pgconn_string() + ) + with psycopg.Connection.connect(conn_string) as conn: + with conn.cursor() as cur: + # 构建SELECT子句 + select_fields = ", ".join(fields) + base_query = f""" + SELECT {select_fields} + FROM public.pipes + """ + + # 如果提供了筛选条件,构建WHERE子句 + if property_conditions: + conditions = [] + params = [] + for key, value in property_conditions.items(): + conditions.append(f"{key} = %s") + params.append(value) + + query = base_query + " WHERE " + " AND ".join(conditions) + cur.execute(query, params) + else: + cur.execute(base_query) + + records = cur.fetchall() + # 将查询结果转换为字典列表 + pipes = [] + for record in records: + pipe_dict = {} + for idx, field in enumerate(fields): + pipe_dict[field] = record[idx] + pipes.append(pipe_dict) + + return pipes + break # 成功 + except Exception as e: + logger.error(f"查询尝试 {attempt + 1} 失败: {e}") + if attempt < max_retries - 1: + time.sleep(1) + else: + raise diff --git a/app/infra/db/postgresql/scada_info.py b/app/infra/db/postgresql/scada_info.py new file mode 100644 index 0000000..40f0504 --- /dev/null +++ b/app/infra/db/postgresql/scada_info.py @@ -0,0 +1,36 @@ +from typing import List, Optional, Any +from psycopg import AsyncConnection + + +class ScadaRepository: + + @staticmethod + async def get_scadas(conn: AsyncConnection) -> List[dict]: + """ + 查询pg数据库中,scada_info 的所有记录 + :param conn: 异步数据库连接 + :return: 包含所有记录的列表,每条记录为一个字典 + """ + async with conn.cursor() as cur: + await cur.execute( + """ + SELECT id, type, associated_element_id, transmission_mode, transmission_frequency, reliability + FROM public.scada_info + """ + ) + records = await cur.fetchall() + # 将查询结果转换为字典列表(假设 record 是字典) + scada_infos = [] + for record in records: + scada_infos.append( + { + "id": record["id"], # 使用字典键 + "type": record["type"], + "associated_element_id": record["associated_element_id"], + "transmission_mode": record["transmission_mode"], + "transmission_frequency": record["transmission_frequency"], + "reliability": record["reliability"], + } + ) + + return scada_infos diff --git a/app/infra/db/postgresql/scheme.py b/app/infra/db/postgresql/scheme.py new file mode 100644 index 0000000..ed9c240 --- /dev/null +++ b/app/infra/db/postgresql/scheme.py @@ -0,0 +1,104 @@ +from typing import List, Optional, Any +from psycopg import AsyncConnection + + +class SchemeRepository: + + @staticmethod + async def get_schemes(conn: AsyncConnection) -> List[dict]: + """ + 查询pg数据库中, scheme_list 的所有记录 + :param conn: 异步数据库连接 + :return: 包含所有记录的列表, 每条记录为一个字典 + """ + async with conn.cursor() as cur: + await cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + """ + ) + records = await cur.fetchall() + + scheme_list = [] + for record in records: + scheme_list.append( + { + "scheme_id": record["scheme_id"], + "scheme_name": record["scheme_name"], + "scheme_type": record["scheme_type"], + "username": record["username"], + "create_time": record["create_time"], + "scheme_start_time": record["scheme_start_time"], + "scheme_detail": record["scheme_detail"], + } + ) + + return scheme_list + + @staticmethod + async def get_burst_locate_results(conn: AsyncConnection) -> List[dict]: + """ + 查询pg数据库中, burst_locate_result 的所有记录 + :param conn: 异步数据库连接 + :return: 包含所有记录的列表, 每条记录为一个字典 + """ + async with conn.cursor() as cur: + await cur.execute( + """ + SELECT id, type, burst_incident, leakage, detect_time, locate_result + FROM public.burst_locate_result + """ + ) + records = await cur.fetchall() + + results = [] + for record in records: + results.append( + { + "id": record["id"], + "type": record["type"], + "burst_incident": record["burst_incident"], + "leakage": record["leakage"], + "detect_time": record["detect_time"], + "locate_result": record["locate_result"], + } + ) + + return results + + @staticmethod + async def get_burst_locate_result_by_incident( + conn: AsyncConnection, burst_incident: str + ) -> List[dict]: + """ + 根据 burst_incident 查询爆管定位结果 + :param conn: 异步数据库连接 + :param burst_incident: 爆管事件标识 + :return: 包含匹配记录的列表 + """ + async with conn.cursor() as cur: + await cur.execute( + """ + SELECT id, type, burst_incident, leakage, detect_time, locate_result + FROM public.burst_locate_result + WHERE burst_incident = %s + """, + (burst_incident,), + ) + records = await cur.fetchall() + + results = [] + for record in records: + results.append( + { + "id": record["id"], + "type": record["type"], + "burst_incident": record["burst_incident"], + "leakage": record["leakage"], + "detect_time": record["detect_time"], + "locate_result": record["locate_result"], + } + ) + + return results diff --git a/app/infra/db/timescaledb/__init__.py b/app/infra/db/timescaledb/__init__.py new file mode 100644 index 0000000..7e1e6c2 --- /dev/null +++ b/app/infra/db/timescaledb/__init__.py @@ -0,0 +1,3 @@ +from .database import * +from .timescaledb_info import * +from .composite_queries import CompositeQueries \ No newline at end of file diff --git a/app/infra/db/timescaledb/composite_queries.py b/app/infra/db/timescaledb/composite_queries.py new file mode 100644 index 0000000..dcf6294 --- /dev/null +++ b/app/infra/db/timescaledb/composite_queries.py @@ -0,0 +1,596 @@ +import time +from typing import List, Optional, Any, Dict, Tuple +from datetime import datetime, timedelta +from psycopg import AsyncConnection +import pandas as pd +import numpy as np +from app.algorithms.cleaning.flow import clean_flow_data_df_kf +from app.algorithms.cleaning.pressure import clean_pressure_data_df_km +from app.algorithms.health.analyzer import PipelineHealthAnalyzer + +from app.infra.db.postgresql.internal_queries import InternalQueries +from app.infra.db.postgresql.scada_info import ScadaRepository as PostgreScadaRepository +from app.infra.db.timescaledb.repositories.realtime import RealtimeRepository +from app.infra.db.timescaledb.repositories.scheme import SchemeRepository +from app.infra.db.timescaledb.repositories.scada import ScadaRepository + + +class CompositeQueries: + """ + 复合查询类,提供跨表查询功能 + """ + + @staticmethod + async def get_scada_associated_realtime_simulation_data( + timescale_conn: AsyncConnection, + postgres_conn: AsyncConnection, + device_ids: List[str], + start_time: datetime, + end_time: datetime, + ) -> Dict[str, List[Dict[str, Any]]]: + """ + 获取 SCADA 关联的 link/node 模拟值 + + 根据传入的 SCADA device_ids,找到关联的 link/node, + 并根据对应的 type,查询对应的模拟数据 + + Args: + timescale_conn: TimescaleDB 异步连接 + postgres_conn: PostgreSQL 异步连接 + device_ids: SCADA 设备ID列表 + start_time: 开始时间 + end_time: 结束时间 + + Returns: + 模拟数据字典,以 device_id 为键,值为数据列表,每个数据包含 time, value 和 scada_id + + Raises: + ValueError: 当 SCADA 设备未找到或字段无效时 + """ + result = {} + # 1. 查询所有 SCADA 信息 + scada_infos = await PostgreScadaRepository.get_scadas(postgres_conn) + + for device_id in device_ids: + # 2. 根据 device_id 找到对应的 SCADA 信息 + target_scada = None + for scada in scada_infos: + if scada["id"] == device_id: + target_scada = scada + break + + if not target_scada: + raise ValueError(f"SCADA device {device_id} not found") + + # 3. 根据 type 和 associated_element_id 查询对应的模拟数据 + element_id = target_scada["associated_element_id"] + scada_type = target_scada["type"] + + if scada_type.lower() == "pipe_flow": + # 查询 link 模拟数据 + res = await RealtimeRepository.get_link_field_by_time_range( + timescale_conn, start_time, end_time, element_id, "flow" + ) + elif scada_type.lower() == "pressure": + # 查询 node 模拟数据 + res = await RealtimeRepository.get_node_field_by_time_range( + timescale_conn, start_time, end_time, element_id, "pressure" + ) + else: + raise ValueError(f"Unknown SCADA type: {scada_type}") + # 添加 scada_id 到每个数据项 + for item in res: + item["scada_id"] = device_id + result[device_id] = res + return result + + @staticmethod + async def get_scada_associated_scheme_simulation_data( + timescale_conn: AsyncConnection, + postgres_conn: AsyncConnection, + device_ids: List[str], + start_time: datetime, + end_time: datetime, + scheme_type: str, + scheme_name: str, + ) -> Dict[str, List[Dict[str, Any]]]: + """ + 获取 SCADA 关联的 link/node scheme 模拟值 + + 根据传入的 SCADA device_ids,找到关联的 link/node, + 并根据对应的 type,查询对应的模拟数据 + + Args: + timescale_conn: TimescaleDB 异步连接 + postgres_conn: PostgreSQL 异步连接 + device_ids: SCADA 设备ID列表 + start_time: 开始时间 + end_time: 结束时间 + + Returns: + 模拟数据字典,以 device_id 为键,值为数据列表,每个数据包含 time, value 和 scada_id + + Raises: + ValueError: 当 SCADA 设备未找到或字段无效时 + """ + result = {} + # 1. 查询所有 SCADA 信息 + scada_infos = await PostgreScadaRepository.get_scadas(postgres_conn) + + for device_id in device_ids: + # 2. 根据 device_id 找到对应的 SCADA 信息 + target_scada = None + for scada in scada_infos: + if scada["id"] == device_id: + target_scada = scada + break + + if not target_scada: + raise ValueError(f"SCADA device {device_id} not found") + + # 3. 根据 type 和 associated_element_id 查询对应的模拟数据 + element_id = target_scada["associated_element_id"] + scada_type = target_scada["type"] + + if scada_type.lower() == "pipe_flow": + # 查询 link 模拟数据 + res = await SchemeRepository.get_link_field_by_scheme_and_time_range( + timescale_conn, + scheme_type, + scheme_name, + start_time, + end_time, + element_id, + "flow", + ) + elif scada_type.lower() == "pressure": + # 查询 node 模拟数据 + res = await SchemeRepository.get_node_field_by_scheme_and_time_range( + timescale_conn, + scheme_type, + scheme_name, + start_time, + end_time, + element_id, + "pressure", + ) + else: + raise ValueError(f"Unknown SCADA type: {scada_type}") + # 添加 scada_id 到每个数据项 + for item in res: + item["scada_id"] = device_id + result[device_id] = res + return result + + @staticmethod + async def get_realtime_simulation_data( + timescale_conn: AsyncConnection, + featureInfos: List[Tuple[str, str]], + start_time: datetime, + end_time: datetime, + ) -> Dict[str, List[Dict[str, Any]]]: + """ + 获取 link/node 模拟值 + + 根据传入的 featureInfos,找到关联的 link/node, + 并根据对应的 type,查询对应的模拟数据 + + Args: + timescale_conn: TimescaleDB 异步连接 + featureInfos: 传入的 feature 信息列表,包含 (element_id, type) + start_time: 开始时间 + end_time: 结束时间 + + Returns: + 模拟数据字典,以 feature_id 为键,值为数据列表,每个数据包含 time, value 和 feature_id + + Raises: + ValueError: 当 SCADA 设备未找到或字段无效时 + """ + result = {} + for feature_id, type in featureInfos: + + if type.lower() == "pipe": + # 查询 link 模拟数据 + res = await RealtimeRepository.get_link_field_by_time_range( + timescale_conn, start_time, end_time, feature_id, "flow" + ) + elif type.lower() == "junction": + # 查询 node 模拟数据 + res = await RealtimeRepository.get_node_field_by_time_range( + timescale_conn, start_time, end_time, feature_id, "pressure" + ) + else: + raise ValueError(f"Unknown type: {type}") + # 添加 scada_id 到每个数据项 + for item in res: + item["feature_id"] = feature_id + result[feature_id] = res + return result + + @staticmethod + async def get_scheme_simulation_data( + timescale_conn: AsyncConnection, + featureInfos: List[Tuple[str, str]], + start_time: datetime, + end_time: datetime, + scheme_type: str, + scheme_name: str, + ) -> Dict[str, List[Dict[str, Any]]]: + """ + 获取 link/node scheme 模拟值 + + 根据传入的 featureInfos,找到关联的 link/node, + 并根据对应的 type,查询对应的模拟数据 + + Args: + timescale_conn: TimescaleDB 异步连接 + featureInfos: 传入的 feature 信息列表,包含 (element_id, type) + start_time: 开始时间 + end_time: 结束时间 + scheme_type: 工况类型 + scheme_name: 工况名称 + + Returns: + 模拟数据字典,以 feature_id 为键,值为数据列表,每个数据包含 time, value 和 feature_id + + Raises: + ValueError: 当类型无效时 + """ + result = {} + for feature_id, type in featureInfos: + if type.lower() == "pipe": + # 查询 link 模拟数据 + res = await SchemeRepository.get_link_field_by_scheme_and_time_range( + timescale_conn, + scheme_type, + scheme_name, + start_time, + end_time, + feature_id, + "flow", + ) + elif type.lower() == "junction": + # 查询 node 模拟数据 + res = await SchemeRepository.get_node_field_by_scheme_and_time_range( + timescale_conn, + scheme_type, + scheme_name, + start_time, + end_time, + feature_id, + "pressure", + ) + else: + raise ValueError(f"Unknown type: {type}") + # 添加 feature_id 到每个数据项 + for item in res: + item["feature_id"] = feature_id + result[feature_id] = res + return result + + @staticmethod + async def get_element_associated_scada_data( + timescale_conn: AsyncConnection, + postgres_conn: AsyncConnection, + element_id: str, + start_time: datetime, + end_time: datetime, + use_cleaned: bool = False, + ) -> Optional[Any]: + """ + 获取 link/node 关联的 SCADA 监测值 + + 根据传入的 link/node id,匹配 SCADA 信息, + 如果存在关联的 SCADA device_id,获取实际的监测数据 + + Args: + timescale_conn: TimescaleDB 异步连接 + postgres_conn: PostgreSQL 异步连接 + element_id: link 或 node 的 ID + start_time: 开始时间 + end_time: 结束时间 + use_cleaned: 是否使用清洗后的数据 (True: "cleaned_value", False: "monitored_value") + + Returns: + SCADA 监测数据值,如果没有找到则返回 None + + Raises: + ValueError: 当元素类型无效时 + """ + + # 1. 查询所有 SCADA 信息 + scada_infos = await PostgreScadaRepository.get_scadas(postgres_conn) + + # 2. 根据 element_type 和 element_id 找到关联的 SCADA 设备 + associated_scada = None + for scada in scada_infos: + if scada["associated_element_id"] == element_id: + associated_scada = scada + break + + if not associated_scada: + # 没有找到关联的 SCADA 设备 + return None + + # 3. 通过 SCADA device_id 获取监测数据 + device_id = associated_scada["id"] + + # 根据 use_cleaned 参数选择字段 + data_field = "cleaned_value" if use_cleaned else "monitored_value" + + # 保证 device_id 以列表形式传递 + res = await ScadaRepository.get_scada_field_by_id_time_range( + timescale_conn, [device_id], start_time, end_time, data_field + ) + + # 将 device_id 替换为 element_id 返回 + return {element_id: res.get(device_id, [])} + + @staticmethod + async def clean_scada_data( + timescale_conn: AsyncConnection, + postgres_conn: AsyncConnection, + device_ids: List[str], + start_time: datetime, + end_time: datetime, + ) -> str: + """ + 清洗 SCADA 数据 + + 根据 device_ids 查询 monitored_value,清洗后更新 cleaned_value + + Args: + timescale_conn: TimescaleDB 连接 + postgres_conn: PostgreSQL 连接 + device_ids: 设备 ID 列表 + start_time: 开始时间 + end_time: 结束时间 + + Returns: + "success" 或错误信息 + """ + try: + # 获取所有 SCADA 信息 + scada_infos = await PostgreScadaRepository.get_scadas(postgres_conn) + # 将列表转换为字典,以 device_id 为键 + scada_device_info_dict = {info["id"]: info for info in scada_infos} + + # 如果 device_ids 为空,则处理所有 SCADA 设备 + if not device_ids: + device_ids = list(scada_device_info_dict.keys()) + + # 批量查询所有设备的数据 + data = await ScadaRepository.get_scada_field_by_id_time_range( + timescale_conn, device_ids, start_time, end_time, "monitored_value" + ) + + if not data: + return "error: fetch none scada data" # 没有数据,直接返回 + + # 将嵌套字典转换为 DataFrame,使用 time 作为索引 + # data 格式: {device_id: [{"time": "...", "value": ...}, ...]} + all_records = [] + for device_id, records in data.items(): + for record in records: + all_records.append( + { + "time": record["time"], + "device_id": device_id, + "value": record["value"], + } + ) + + if not all_records: + return "error: fetch none scada data" # 没有数据,直接返回 + + # 创建 DataFrame 并透视,使 device_id 成为列 + df_long = pd.DataFrame(all_records) + df = df_long.pivot(index="time", columns="device_id", values="value") + + # 根据type分类设备 + pressure_ids = [ + id + for id in df.columns + if scada_device_info_dict.get(id, {}).get("type") == "pressure" + ] + flow_ids = [ + id + for id in df.columns + if scada_device_info_dict.get(id, {}).get("type") == "pipe_flow" + ] + + # 处理pressure数据 + if pressure_ids: + pressure_df = df[pressure_ids] + # 重置索引,将 time 变为普通列 + pressure_df = pressure_df.reset_index() + # 调用清洗方法 + cleaned_df = clean_pressure_data_df_km(pressure_df) + # 将清洗后的数据写回数据库 + for device_id in pressure_ids: + if device_id in cleaned_df.columns: + cleaned_values = cleaned_df[device_id].tolist() + time_values = cleaned_df["time"].tolist() + for i, time_str in enumerate(time_values): + time_dt = datetime.fromisoformat(time_str) + value = cleaned_values[i] + await ScadaRepository.update_scada_field( + timescale_conn, + time_dt, + device_id, + "cleaned_value", + value, + ) + + # 处理flow数据 + if flow_ids: + flow_df = df[flow_ids] + # 重置索引,将 time 变为普通列 + flow_df = flow_df.reset_index() + # 调用清洗方法 + cleaned_df = clean_flow_data_df_kf(flow_df) + # 将清洗后的数据写回数据库 + for device_id in flow_ids: + if device_id in cleaned_df.columns: + cleaned_values = cleaned_df[device_id].tolist() + time_values = cleaned_df["time"].tolist() + for i, time_str in enumerate(time_values): + time_dt = datetime.fromisoformat(time_str) + value = cleaned_values[i] + await ScadaRepository.update_scada_field( + timescale_conn, + time_dt, + device_id, + "cleaned_value", + value, + ) + + return "success" + except Exception as e: + return f"error: {str(e)}" + + @staticmethod + async def predict_pipeline_health( + timescale_conn: AsyncConnection, + network_name: str, + query_time: datetime, + ) -> List[Dict[str, Any]]: + """ + 预测管道健康状况 + + 根据管网名称和当前时间,查询管道信息和实时数据, + 使用随机生存森林模型预测管道的生存概率 + + Args: + timescale_conn: TimescaleDB 异步连接 + db_name: 管网数据库名称 + query_time: 查询时间 + property_conditions: 可选的管道筛选条件,如 {"diameter": 300} + + Returns: + 预测结果列表,每个元素包含 link_id 和对应的生存函数 + + Raises: + ValueError: 当参数无效或数据不足时 + FileNotFoundError: 当模型文件未找到时 + """ + try: + # 1. 准备时间范围(查询时间前后1秒) + start_time = query_time - timedelta(seconds=1) + end_time = query_time + timedelta(seconds=1) + + # 2. 先查询流速数据(velocity),获取有数据的管道ID列表 + velocity_data = await RealtimeRepository.get_links_field_by_time_range( + timescale_conn, start_time, end_time, "velocity" + ) + + if not velocity_data: + raise ValueError("未找到流速数据") + + # 3. 只查询有流速数据的管道的基本信息 + valid_link_ids = list(velocity_data.keys()) + + # 批量查询这些管道的详细信息 + fields = ["id", "diameter", "node1", "node2"] + all_links = InternalQueries.get_links_by_property( + fields=fields, + db_name=network_name, + ) + + # 转换为字典以快速查找 + links_dict = {link["id"]: link for link in all_links} + + # 获取所有需要查询的节点ID + node_ids = set() + for link_id in valid_link_ids: + if link_id in links_dict: + link = links_dict[link_id] + node_ids.add(link["node1"]) + node_ids.add(link["node2"]) + + # 4. 批量查询压力数据(pressure) + pressure_data = await RealtimeRepository.get_nodes_field_by_time_range( + timescale_conn, start_time, end_time, "pressure" + ) + + # 5. 组合数据结构 + materials = [] + diameters = [] + velocities = [] + pressures = [] + link_ids = [] + + for link_id in valid_link_ids: + # 跳过不在管道字典中的ID(如泵等其他元素) + if link_id not in links_dict: + continue + + link = links_dict[link_id] + diameter = link["diameter"] + node1 = link["node1"] + node2 = link["node2"] + + # 获取流速数据 + velocity_values = velocity_data[link_id] + velocity = velocity_values[-1]["value"] if velocity_values else 0 + + # 获取node1和node2的压力数据,计算平均值 + node1_pressure = 0 + node2_pressure = 0 + + if node1 in pressure_data and pressure_data[node1]: + pressure_values = pressure_data[node1] + node1_pressure = ( + pressure_values[-1]["value"] if pressure_values else 0 + ) + + if node2 in pressure_data and pressure_data[node2]: + pressure_values = pressure_data[node2] + node2_pressure = ( + pressure_values[-1]["value"] if pressure_values else 0 + ) + + # 计算平均压力 + avg_pressure = (node1_pressure + node2_pressure) / 2 + + # 添加到列表 + link_ids.append(link_id) + materials.append(7) # 默认材料类型为7,可根据实际情况调整 + diameters.append(diameter) + velocities.append(velocity) + pressures.append(avg_pressure) + + if not link_ids: + raise ValueError("没有找到有效的管道数据用于预测") + + # 6. 创建DataFrame + data = pd.DataFrame( + { + "Material": materials, + "Diameter": diameters, + "Flow Velocity": velocities, + "Pressure": pressures, + } + ) + + # 7. 使用PipelineHealthAnalyzer进行预测 + analyzer = PipelineHealthAnalyzer() + survival_functions = analyzer.predict_survival(data) + # 8. 组合结果 + results = [] + for i, link_id in enumerate(link_ids): + sf = survival_functions[i] + results.append( + { + "link_id": link_id, + "survival_function": { + "x": sf.x.tolist(), # 时间点(年) + "y": sf.y.tolist(), # 生存概率 + }, + } + ) + return results + + except Exception as e: + raise ValueError(f"管道健康预测失败: {str(e)}") diff --git a/app/infra/db/timescaledb/database.py b/app/infra/db/timescaledb/database.py new file mode 100644 index 0000000..12f33e2 --- /dev/null +++ b/app/infra/db/timescaledb/database.py @@ -0,0 +1,124 @@ +import logging +from contextlib import asynccontextmanager +from typing import AsyncGenerator, Dict, Optional +import psycopg_pool +from psycopg.rows import dict_row +import app.infra.db.timescaledb.timescaledb_info as timescaledb_info + +# Configure logging +logger = logging.getLogger(__name__) + + +class Database: + def __init__(self, db_name=None): + self.pool = None + self.db_name = db_name + + def init_pool(self, db_name=None): + """Initialize the connection pool.""" + # Use provided db_name, or the one from constructor, or default from config + target_db_name = db_name or self.db_name + + # Get connection string, handling default case where target_db_name might be None + if target_db_name: + conn_string = timescaledb_info.get_pgconn_string(db_name=target_db_name) + else: + conn_string = timescaledb_info.get_pgconn_string() + + try: + self.pool = psycopg_pool.AsyncConnectionPool( + conninfo=conn_string, + min_size=5, + max_size=20, + open=False, # Don't open immediately, wait for startup + kwargs={"row_factory": dict_row}, # Return rows as dictionaries + ) + logger.info( + f"TimescaleDB connection pool initialized for database: {target_db_name or 'default'}" + ) + except Exception as e: + logger.error(f"Failed to initialize TimescaleDB connection pool: {e}") + raise + + async def open(self): + if self.pool: + await self.pool.open() + + async def close(self): + """Close the connection pool.""" + if self.pool: + await self.pool.close() + logger.info("TimescaleDB connection pool closed.") + + def get_pgconn_string(self, db_name=None): + """Get the TimescaleDB connection string.""" + target_db_name = db_name or self.db_name + if target_db_name: + return timescaledb_info.get_pgconn_string(db_name=target_db_name) + return timescaledb_info.get_pgconn_string() + + @asynccontextmanager + async def get_connection(self) -> AsyncGenerator: + """Get a connection from the pool.""" + if not self.pool: + raise Exception("Database pool is not initialized.") + + async with self.pool.connection() as conn: + yield conn + + +# 默认数据库实例 +db = Database() + +# 缓存不同数据库的实例 - 避免重复创建连接池 +_database_instances: Dict[str, Database] = {} + + +def create_database_instance(db_name): + """Create a new Database instance for a specific database.""" + return Database(db_name=db_name) + + +async def get_database_instance(db_name: Optional[str] = None) -> Database: + """Get or create a database instance for the specified database name.""" + if not db_name: + return db # 返回默认数据库实例 + + if db_name not in _database_instances: + # 创建新的数据库实例 + instance = create_database_instance(db_name) + instance.init_pool() + await instance.open() + _database_instances[db_name] = instance + logger.info(f"Created new database instance for: {db_name}") + + return _database_instances[db_name] + + +async def get_db_connection(): + """Dependency for FastAPI to get a database connection.""" + async with db.get_connection() as conn: + yield conn + + +async def get_database_connection(db_name: Optional[str] = None): + """ + FastAPI dependency to get database connection with optional database name. + 使用方法: conn: AsyncConnection = Depends(lambda: get_database_connection("your_db_name")) + 或在路由函数中: conn: AsyncConnection = Depends(get_database_connection) + """ + instance = await get_database_instance(db_name) + async with instance.get_connection() as conn: + yield conn + + +async def cleanup_database_instances(): + """Clean up all database instances (call this on application shutdown).""" + for db_name, instance in _database_instances.items(): + await instance.close() + logger.info(f"Closed database instance for: {db_name}") + _database_instances.clear() + + # 关闭默认数据库 + await db.close() + logger.info("All database instances cleaned up.") diff --git a/app/infra/db/timescaledb/internal_queries.py b/app/infra/db/timescaledb/internal_queries.py new file mode 100644 index 0000000..8c508ba --- /dev/null +++ b/app/infra/db/timescaledb/internal_queries.py @@ -0,0 +1,330 @@ +from typing import List + +from fastapi.logger import logger +from datetime import datetime, timedelta +import psycopg +from psycopg import sql +from psycopg.rows import dict_row +import time +from app.infra.db.timescaledb.repositories.scheme import SchemeRepository +from app.infra.db.timescaledb.repositories.realtime import RealtimeRepository +import app.infra.db.timescaledb.timescaledb_info as timescaledb_info +from app.infra.db.timescaledb.repositories.scada import ScadaRepository + + +class InternalStorage: + @staticmethod + def store_realtime_simulation( + node_result_list: List[dict], + link_result_list: List[dict], + result_start_time: str, + db_name: str = None, + max_retries: int = 3, + ): + """存储实时模拟结果""" + for attempt in range(max_retries): + try: + conn_string = ( + timescaledb_info.get_pgconn_string(db_name=db_name) + if db_name + else timescaledb_info.get_pgconn_string() + ) + with psycopg.Connection.connect(conn_string) as conn: + RealtimeRepository.store_realtime_simulation_result_sync( + conn, node_result_list, link_result_list, result_start_time + ) + break # 成功 + except Exception as e: + logger.error(f"存储尝试 {attempt + 1} 失败: {e}") + if attempt < max_retries - 1: + time.sleep(1) # 重试前等待 + else: + raise # 达到最大重试次数后抛出异常 + + @staticmethod + def store_scheme_simulation( + scheme_type: str, + scheme_name: str, + node_result_list: List[dict], + link_result_list: List[dict], + result_start_time: str, + num_periods: int = 1, + db_name: str = None, + max_retries: int = 3, + ): + """存储方案模拟结果""" + for attempt in range(max_retries): + try: + conn_string = ( + timescaledb_info.get_pgconn_string(db_name=db_name) + if db_name + else timescaledb_info.get_pgconn_string() + ) + with psycopg.Connection.connect(conn_string) as conn: + SchemeRepository.store_scheme_simulation_result_sync( + conn, + scheme_type, + scheme_name, + node_result_list, + link_result_list, + result_start_time, + num_periods, + ) + break # 成功 + except Exception as e: + logger.error(f"存储尝试 {attempt + 1} 失败: {e}") + if attempt < max_retries - 1: + time.sleep(1) # 重试前等待 + else: + raise # 达到最大重试次数后抛出异常 + + +class InternalQueries: + @staticmethod + def query_scada_by_ids_time( + device_ids: List[str], + query_time: str, + db_name: str = None, + max_retries: int = 3, + ) -> dict: + """查询指定时间点的 SCADA 数据""" + + # 解析时间,假设是北京时间 + beijing_time = datetime.fromisoformat(query_time) + start_time = beijing_time - timedelta(seconds=1) + end_time = beijing_time + timedelta(seconds=1) + + for attempt in range(max_retries): + try: + conn_string = ( + timescaledb_info.get_pgconn_string(db_name=db_name) + if db_name + else timescaledb_info.get_pgconn_string() + ) + with psycopg.Connection.connect(conn_string) as conn: + rows = ScadaRepository.get_scada_by_ids_time_range_sync( + conn, device_ids, start_time, end_time + ) + # 处理结果,返回每个 device_id 的第一个值 + result = {} + for device_id in device_ids: + device_rows = [ + row for row in rows if row["device_id"] == device_id + ] + if device_rows: + result[device_id] = device_rows[0]["monitored_value"] + else: + result[device_id] = None + return result + except Exception as e: + logger.error(f"查询尝试 {attempt + 1} 失败: {e}") + if attempt < max_retries - 1: + time.sleep(1) + else: + raise + + @staticmethod + def query_scada_by_ids_timerange( + device_ids: List[str], + start_time: str | datetime, + end_time: str | datetime, + db_name: str = None, + max_retries: int = 3, + ) -> dict[str, list[dict]]: + """查询指定时间窗的 SCADA 数据,返回 {device_id: [{time, value}, ...]}。""" + start_dt = ( + datetime.fromisoformat(start_time) + if isinstance(start_time, str) + else start_time + ) + end_dt = ( + datetime.fromisoformat(end_time) if isinstance(end_time, str) else end_time + ) + + for attempt in range(max_retries): + try: + conn_string = ( + timescaledb_info.get_pgconn_string(db_name=db_name) + if db_name + else timescaledb_info.get_pgconn_string() + ) + with psycopg.Connection.connect(conn_string) as conn: + rows = ScadaRepository.get_scada_by_ids_time_range_sync( + conn, device_ids, start_dt, end_dt + ) + result: dict[str, list[dict]] = { + device_id: [] for device_id in device_ids + } + for row in rows: + device_id = row["device_id"] + value = row.get("cleaned_value") + if value is None: + value = row.get("monitored_value") + result.setdefault(device_id, []).append( + {"time": row["time"].isoformat(), "value": value} + ) + for device_id in result: + result[device_id].sort(key=lambda item: item["time"]) + return result + except Exception as e: + logger.error(f"查询尝试 {attempt + 1} 失败: {e}") + if attempt < max_retries - 1: + time.sleep(1) + else: + raise + + @staticmethod + def query_realtime_simulation_by_ids_timerange( + element_ids: List[str], + start_time: str | datetime, + end_time: str | datetime, + element_type: str, + field: str, + db_name: str = None, + max_retries: int = 3, + ) -> dict[str, list[dict]]: + """查询实时模拟结果,返回 {id: [{time, value}, ...]}。""" + return InternalQueries._query_simulation_by_ids_timerange( + schema_name="realtime", + element_ids=element_ids, + start_time=start_time, + end_time=end_time, + element_type=element_type, + field=field, + db_name=db_name, + max_retries=max_retries, + ) + + @staticmethod + def query_scheme_simulation_by_ids_timerange( + element_ids: List[str], + start_time: str | datetime, + end_time: str | datetime, + element_type: str, + field: str, + scheme_type: str, + scheme_name: str, + db_name: str = None, + max_retries: int = 3, + ) -> dict[str, list[dict]]: + """查询方案模拟结果,返回 {id: [{time, value}, ...]}。""" + return InternalQueries._query_simulation_by_ids_timerange( + schema_name="scheme", + element_ids=element_ids, + start_time=start_time, + end_time=end_time, + element_type=element_type, + field=field, + db_name=db_name, + max_retries=max_retries, + scheme_type=scheme_type, + scheme_name=scheme_name, + ) + + @staticmethod + def _query_simulation_by_ids_timerange( + *, + schema_name: str, + element_ids: List[str], + start_time: str | datetime, + end_time: str | datetime, + element_type: str, + field: str, + db_name: str = None, + max_retries: int = 3, + scheme_type: str | None = None, + scheme_name: str | None = None, + ) -> dict[str, list[dict]]: + if not element_ids: + return {} + + start_dt = ( + datetime.fromisoformat(start_time) + if isinstance(start_time, str) + else start_time + ) + end_dt = ( + datetime.fromisoformat(end_time) if isinstance(end_time, str) else end_time + ) + table_name, valid_fields = InternalQueries._resolve_simulation_table(element_type) + if field not in valid_fields: + raise ValueError(f"Invalid field for {element_type}: {field}") + if schema_name not in {"realtime", "scheme"}: + raise ValueError(f"Unsupported schema_name: {schema_name}") + if schema_name == "scheme" and (not scheme_type or not scheme_name): + raise ValueError("scheme 查询必须提供 scheme_type 和 scheme_name。") + + for attempt in range(max_retries): + try: + conn_string = ( + timescaledb_info.get_pgconn_string(db_name=db_name) + if db_name + else timescaledb_info.get_pgconn_string() + ) + with psycopg.Connection.connect(conn_string) as conn: + with conn.cursor(row_factory=dict_row) as cur: + if schema_name == "scheme": + query = sql.SQL( + "SELECT id, time, {} FROM {}.{} " + "WHERE scheme_type = %s AND scheme_name = %s " + "AND time >= %s AND time <= %s AND id = ANY(%s)" + ).format( + sql.Identifier(field), + sql.Identifier(schema_name), + sql.Identifier(table_name), + ) + cur.execute( + query, + ( + scheme_type, + scheme_name, + start_dt, + end_dt, + element_ids, + ), + ) + else: + query = sql.SQL( + "SELECT id, time, {} FROM {}.{} " + "WHERE time >= %s AND time <= %s AND id = ANY(%s)" + ).format( + sql.Identifier(field), + sql.Identifier(schema_name), + sql.Identifier(table_name), + ) + cur.execute(query, (start_dt, end_dt, element_ids)) + rows = cur.fetchall() + result: dict[str, list[dict]] = { + element_id: [] for element_id in element_ids + } + for row in rows: + result.setdefault(row["id"], []).append( + {"time": row["time"].isoformat(), "value": row[field]} + ) + for element_id in result: + result[element_id].sort(key=lambda item: item["time"]) + return result + except Exception as e: + logger.error(f"查询尝试 {attempt + 1} 失败: {e}") + if attempt < max_retries - 1: + time.sleep(1) + else: + raise + + @staticmethod + def _resolve_simulation_table(element_type: str) -> tuple[str, set[str]]: + normalized_type = element_type.lower() + if normalized_type == "node": + return "node_simulation", {"actual_demand", "total_head", "pressure", "quality"} + if normalized_type == "link": + return "link_simulation", { + "flow", + "friction", + "headloss", + "quality", + "reaction", + "setting", + "status", + "velocity", + } + raise ValueError(f"Unsupported element_type: {element_type}") diff --git a/app/infra/db/timescaledb/repositories/__init__.py b/app/infra/db/timescaledb/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/infra/db/timescaledb/repositories/realtime.py b/app/infra/db/timescaledb/repositories/realtime.py new file mode 100644 index 0000000..06a32de --- /dev/null +++ b/app/infra/db/timescaledb/repositories/realtime.py @@ -0,0 +1,647 @@ +from typing import List, Any, Dict +from datetime import datetime, timedelta, timezone +from collections import defaultdict +from psycopg import AsyncConnection, Connection, sql + +# 定义UTC+8时区 +UTC_8 = timezone(timedelta(hours=8)) + + +class RealtimeRepository: + + # --- Link Simulation --- + + @staticmethod + async def insert_links_batch(conn: AsyncConnection, data: List[dict]): + """Batch insert for realtime.link_simulation using DELETE then COPY for performance.""" + if not data: + return + + # 假设同一批次的数据时间是相同的 + target_time = data[0]["time"] + + # 使用事务确保原子性 + async with conn.transaction(): + async with conn.cursor() as cur: + # 1. 先删除该时间点的旧数据 + await cur.execute( + "DELETE FROM realtime.link_simulation WHERE time = %s", + (target_time,), + ) + + # 2. 使用 COPY 快速写入新数据 + async with cur.copy( + "COPY realtime.link_simulation (time, id, flow, friction, headloss, quality, reaction, setting, status, velocity) FROM STDIN" + ) as copy: + for item in data: + await copy.write_row( + ( + item["time"], + item["id"], + item.get("flow"), + item.get("friction"), + item.get("headloss"), + item.get("quality"), + item.get("reaction"), + item.get("setting"), + item.get("status"), + item.get("velocity"), + ) + ) + + @staticmethod + def insert_links_batch_sync(conn: Connection, data: List[dict]): + """Batch insert for realtime.link_simulation using DELETE then COPY for performance (sync version).""" + if not data: + return + + # 假设同一批次的数据时间是相同的 + target_time = data[0]["time"] + + # 使用事务确保原子性 + with conn.transaction(): + with conn.cursor() as cur: + # 1. 先删除该时间点的旧数据 + cur.execute( + "DELETE FROM realtime.link_simulation WHERE time = %s", + (target_time,), + ) + + # 2. 使用 COPY 快速写入新数据 + with cur.copy( + "COPY realtime.link_simulation (time, id, flow, friction, headloss, quality, reaction, setting, status, velocity) FROM STDIN" + ) as copy: + for item in data: + copy.write_row( + ( + item["time"], + item["id"], + item.get("flow"), + item.get("friction"), + item.get("headloss"), + item.get("quality"), + item.get("reaction"), + item.get("setting"), + item.get("status"), + item.get("velocity"), + ) + ) + + @staticmethod + async def get_link_by_time_range( + conn: AsyncConnection, start_time: datetime, end_time: datetime, link_id: str + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM realtime.link_simulation WHERE time >= %s AND time <= %s AND id = %s", + (start_time, end_time, link_id), + ) + return await cur.fetchall() + + @staticmethod + async def get_links_by_time_range( + conn: AsyncConnection, start_time: datetime, end_time: datetime + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM realtime.link_simulation WHERE time >= %s AND time <= %s", + (start_time, end_time), + ) + return await cur.fetchall() + + @staticmethod + async def get_link_field_by_time_range( + conn: AsyncConnection, + start_time: datetime, + end_time: datetime, + link_id: str, + field: str, + ) -> List[Dict[str, Any]]: + # Validate field name to prevent SQL injection + valid_fields = { + "flow", + "friction", + "headloss", + "quality", + "reaction", + "setting", + "status", + "velocity", + } + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT time, {} FROM realtime.link_simulation WHERE time >= %s AND time <= %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (start_time, end_time, link_id)) + rows = await cur.fetchall() + return [ + {"time": row["time"].isoformat(), "value": row[field]} for row in rows + ] + + @staticmethod + async def get_links_field_by_time_range( + conn: AsyncConnection, + start_time: datetime, + end_time: datetime, + field: str, + ) -> dict: + # Validate field name to prevent SQL injection + valid_fields = { + "flow", + "friction", + "headloss", + "quality", + "reaction", + "setting", + "status", + "velocity", + } + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT id, time, {} FROM realtime.link_simulation WHERE time >= %s AND time <= %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (start_time, end_time)) + rows = await cur.fetchall() + result = defaultdict(list) + for row in rows: + result[row["id"]].append( + {"time": row["time"].isoformat(), "value": row[field]} + ) + return dict(result) + + @staticmethod + async def update_link_field( + conn: AsyncConnection, + time: datetime, + link_id: str, + field: str, + value: Any, + ): + valid_fields = { + "flow", + "friction", + "headloss", + "quality", + "reaction", + "setting", + "status", + "velocity", + } + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "UPDATE realtime.link_simulation SET {} = %s WHERE time = %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (value, time, link_id)) + + @staticmethod + async def delete_links_by_time_range( + conn: AsyncConnection, start_time: datetime, end_time: datetime + ): + async with conn.cursor() as cur: + await cur.execute( + "DELETE FROM realtime.link_simulation WHERE time >= %s AND time <= %s", + (start_time, end_time), + ) + + # --- Node Simulation --- + + @staticmethod + async def insert_nodes_batch(conn: AsyncConnection, data: List[dict]): + if not data: + return + + # 假设同一批次的数据时间是相同的 + target_time = data[0]["time"] + + # 使用事务确保原子性 + async with conn.transaction(): + async with conn.cursor() as cur: + # 1. 先删除该时间点的旧数据 + await cur.execute( + "DELETE FROM realtime.node_simulation WHERE time = %s", + (target_time,), + ) + + # 2. 使用 COPY 快速写入新数据 + async with cur.copy( + "COPY realtime.node_simulation (time, id, actual_demand, total_head, pressure, quality) FROM STDIN" + ) as copy: + for item in data: + await copy.write_row( + ( + item["time"], + item["id"], + item.get("actual_demand"), + item.get("total_head"), + item.get("pressure"), + item.get("quality"), + ) + ) + + @staticmethod + def insert_nodes_batch_sync(conn: Connection, data: List[dict]): + if not data: + return + + # 假设同一批次的数据时间是相同的 + target_time = data[0]["time"] + + # 使用事务确保原子性 + with conn.transaction(): + with conn.cursor() as cur: + # 1. 先删除该时间点的旧数据 + cur.execute( + "DELETE FROM realtime.node_simulation WHERE time = %s", + (target_time,), + ) + + # 2. 使用 COPY 快速写入新数据 + with cur.copy( + "COPY realtime.node_simulation (time, id, actual_demand, total_head, pressure, quality) FROM STDIN" + ) as copy: + for item in data: + copy.write_row( + ( + item["time"], + item["id"], + item.get("actual_demand"), + item.get("total_head"), + item.get("pressure"), + item.get("quality"), + ) + ) + + @staticmethod + async def get_node_by_time_range( + conn: AsyncConnection, start_time: datetime, end_time: datetime, node_id: str + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM realtime.node_simulation WHERE time >= %s AND time <= %s AND id = %s", + (start_time, end_time, node_id), + ) + return await cur.fetchall() + + @staticmethod + async def get_nodes_by_time_range( + conn: AsyncConnection, start_time: datetime, end_time: datetime + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM realtime.node_simulation WHERE time >= %s AND time <= %s", + (start_time, end_time), + ) + return await cur.fetchall() + + @staticmethod + async def get_node_field_by_time_range( + conn: AsyncConnection, + start_time: datetime, + end_time: datetime, + node_id: str, + field: str, + ) -> List[Dict[str, Any]]: + valid_fields = {"actual_demand", "total_head", "pressure", "quality"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT time, {} FROM realtime.node_simulation WHERE time >= %s AND time <= %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (start_time, end_time, node_id)) + rows = await cur.fetchall() + return [ + {"time": row["time"].isoformat(), "value": row[field]} for row in rows + ] + + @staticmethod + async def get_nodes_field_by_time_range( + conn: AsyncConnection, start_time: datetime, end_time: datetime, field: str + ) -> dict: + valid_fields = {"actual_demand", "total_head", "pressure", "quality"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT id, time, {} FROM realtime.node_simulation WHERE time >= %s AND time <= %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (start_time, end_time)) + rows = await cur.fetchall() + result = defaultdict(list) + for row in rows: + result[row["id"]].append( + {"time": row["time"].isoformat(), "value": row[field]} + ) + return dict(result) + + @staticmethod + async def update_node_field( + conn: AsyncConnection, + time: datetime, + node_id: str, + field: str, + value: Any, + ): + valid_fields = {"actual_demand", "total_head", "pressure", "quality"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "UPDATE realtime.node_simulation SET {} = %s WHERE time = %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (value, time, node_id)) + + @staticmethod + async def delete_nodes_by_time_range( + conn: AsyncConnection, start_time: datetime, end_time: datetime + ): + async with conn.cursor() as cur: + await cur.execute( + "DELETE FROM realtime.node_simulation WHERE time >= %s AND time <= %s", + (start_time, end_time), + ) + + # --- 复合查询 --- + + @staticmethod + async def store_realtime_simulation_result( + conn: AsyncConnection, + node_result_list: List[Dict[str, any]], + link_result_list: List[Dict[str, any]], + result_start_time: str, + ): + """ + Store realtime simulation results to TimescaleDB. + + Args: + conn: Database connection + node_result_list: List of node simulation results + link_result_list: List of link simulation results + result_start_time: Start time for the results (ISO format string) + """ + # Convert result_start_time string to datetime if needed + if isinstance(result_start_time, str): + # 如果是ISO格式字符串,解析并转换为UTC+8 + if result_start_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat( + result_start_time.replace("Z", "+00:00") + ) + simulation_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + simulation_time = datetime.fromisoformat(result_start_time) + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + else: + simulation_time = result_start_time + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + + # Prepare node data for batch insert + node_data = [] + for node_result in node_result_list: + node_id = node_result.get("node") + data = node_result.get("result", [])[0] # 实时模拟只有一个周期 + node_data.append( + { + "time": simulation_time, + "id": node_id, + "actual_demand": data.get("demand"), + "total_head": data.get("head"), + "pressure": data.get("pressure"), + "quality": data.get("quality"), + } + ) + + # Prepare link data for batch insert + link_data = [] + for link_result in link_result_list: + link_id = link_result.get("link") + data = link_result.get("result", [])[0] + link_data.append( + { + "time": simulation_time, + "id": link_id, + "flow": data.get("flow"), + "friction": data.get("friction"), + "headloss": data.get("headloss"), + "quality": data.get("quality"), + "reaction": data.get("reaction"), + "setting": data.get("setting"), + "status": data.get("status"), + "velocity": data.get("velocity"), + } + ) + + # Insert data using batch methods + if node_data: + await RealtimeRepository.insert_nodes_batch(conn, node_data) + + if link_data: + await RealtimeRepository.insert_links_batch(conn, link_data) + + @staticmethod + def store_realtime_simulation_result_sync( + conn: Connection, + node_result_list: List[Dict[str, any]], + link_result_list: List[Dict[str, any]], + result_start_time: str, + ): + """ + Store realtime simulation results to TimescaleDB (sync version). + + Args: + conn: Database connection + node_result_list: List of node simulation results + link_result_list: List of link simulation results + result_start_time: Start time for the results (ISO format string) + """ + # Convert result_start_time string to datetime if needed + if isinstance(result_start_time, str): + # 如果是ISO格式字符串,解析并转换为UTC+8 + if result_start_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat( + result_start_time.replace("Z", "+00:00") + ) + simulation_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + simulation_time = datetime.fromisoformat(result_start_time) + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + else: + simulation_time = result_start_time + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + + # Prepare node data for batch insert + node_data = [] + for node_result in node_result_list: + node_id = node_result.get("node") + data = node_result.get("result", [])[0] # 实时模拟只有一个周期 + node_data.append( + { + "time": simulation_time, + "id": node_id, + "actual_demand": data.get("demand"), + "total_head": data.get("head"), + "pressure": data.get("pressure"), + "quality": data.get("quality"), + } + ) + + # Prepare link data for batch insert + link_data = [] + for link_result in link_result_list: + link_id = link_result.get("link") + data = link_result.get("result", [])[0] + link_data.append( + { + "time": simulation_time, + "id": link_id, + "flow": data.get("flow"), + "friction": data.get("friction"), + "headloss": data.get("headloss"), + "quality": data.get("quality"), + "reaction": data.get("reaction"), + "setting": data.get("setting"), + "status": data.get("status"), + "velocity": data.get("velocity"), + } + ) + + # Insert data using batch methods + if node_data: + RealtimeRepository.insert_nodes_batch_sync(conn, node_data) + + if link_data: + RealtimeRepository.insert_links_batch_sync(conn, link_data) + + @staticmethod + async def query_all_record_by_time_property( + conn: AsyncConnection, + query_time: str, + type: str, + property: str, + ) -> list: + """ + Query all records by time and property from TimescaleDB. + + Args: + conn: Database connection + query_time: Time to query (ISO format string) + type: Type of data ("node" or "link") + property: Property/field to query + + Returns: + List of records matching the criteria + """ + # Convert query_time string to datetime + if isinstance(query_time, str): + if query_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat(query_time.replace("Z", "+00:00")) + target_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + target_time = datetime.fromisoformat(query_time) + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + else: + target_time = query_time + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + + # Create time range: query_time ± 1 second + start_time = target_time - timedelta(seconds=1) + end_time = target_time + timedelta(seconds=1) + + # Query based on type + if type.lower() == "node": + data = await RealtimeRepository.get_nodes_field_by_time_range( + conn, start_time, end_time, property + ) + elif type.lower() == "link": + data = await RealtimeRepository.get_links_field_by_time_range( + conn, start_time, end_time, property + ) + else: + raise ValueError(f"Invalid type: {type}. Must be 'node' or 'link'") + + # Format the results + result = [] + for id, items in data.items(): + for item in items: + result.append({"ID": id, "value": item["value"]}) + return result + + @staticmethod + async def query_simulation_result_by_id_time( + conn: AsyncConnection, + id: str, + type: str, + query_time: str, + ) -> list[dict]: + """ + Query simulation results by id and time from TimescaleDB. + + Args: + conn: Database connection + id: The id of the node or link + type: Type of data ("node" or "link") + query_time: Time to query (ISO format string) + + Returns: + List of records matching the criteria + """ + # Convert query_time string to datetime + if isinstance(query_time, str): + if query_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat(query_time.replace("Z", "+00:00")) + target_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + target_time = datetime.fromisoformat(query_time) + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + else: + target_time = query_time + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + + # Create time range: query_time ± 1 second + start_time = target_time - timedelta(seconds=1) + end_time = target_time + timedelta(seconds=1) + + # Query based on type + if type.lower() == "node": + return await RealtimeRepository.get_node_by_time_range( + conn, start_time, end_time, id + ) + elif type.lower() == "link": + return await RealtimeRepository.get_link_by_time_range( + conn, start_time, end_time, id + ) + else: + raise ValueError(f"Invalid type: {type}. Must be 'node' or 'link'") diff --git a/app/infra/db/timescaledb/repositories/scada.py b/app/infra/db/timescaledb/repositories/scada.py new file mode 100644 index 0000000..bc8717f --- /dev/null +++ b/app/infra/db/timescaledb/repositories/scada.py @@ -0,0 +1,107 @@ +from typing import List, Any +from datetime import datetime +from collections import defaultdict +from psycopg import AsyncConnection, Connection, sql +from psycopg.rows import dict_row + + +class ScadaRepository: + + @staticmethod + async def insert_scada_batch(conn: AsyncConnection, data: List[dict]): + if not data: + return + + async with conn.cursor() as cur: + async with cur.copy( + "COPY scada.scada_data (time, device_id, monitored_value, cleaned_value) FROM STDIN" + ) as copy: + for item in data: + await copy.write_row( + ( + item["time"], + item["device_id"], + item.get("monitored_value"), + item.get("cleaned_value"), + ) + ) + + @staticmethod + async def get_scada_by_ids_time_range( + conn: AsyncConnection, + device_ids: List[str], + start_time: datetime, + end_time: datetime, + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM scada.scada_data WHERE device_id = ANY(%s) AND time >= %s AND time <= %s", + (device_ids, start_time, end_time), + ) + return await cur.fetchall() + + @staticmethod + def get_scada_by_ids_time_range_sync( + conn: Connection, + device_ids: List[str], + start_time: datetime, + end_time: datetime, + ) -> List[dict]: + with conn.cursor(row_factory=dict_row) as cur: + cur.execute( + "SELECT * FROM scada.scada_data WHERE device_id = ANY(%s) AND time >= %s AND time <= %s", + (device_ids, start_time, end_time), + ) + return cur.fetchall() + + @staticmethod + async def get_scada_field_by_id_time_range( + conn: AsyncConnection, + device_ids: List[str], + start_time: datetime, + end_time: datetime, + field: str, + ) -> dict: + valid_fields = {"monitored_value", "cleaned_value"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT device_id, time, {} FROM scada.scada_data WHERE time >= %s AND time <= %s AND device_id = ANY(%s)" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (start_time, end_time, device_ids)) + rows = await cur.fetchall() + result = defaultdict(list) + for row in rows: + result[row["device_id"]].append({ + "time": row["time"].isoformat(), + "value": row[field] + }) + return dict(result) + + @staticmethod + async def update_scada_field( + conn: AsyncConnection, time: datetime, device_id: str, field: str, value: Any + ): + valid_fields = {"monitored_value", "cleaned_value"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "UPDATE scada.scada_data SET {} = %s WHERE time = %s AND device_id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (value, time, device_id)) + + @staticmethod + async def delete_scada_by_id_time_range( + conn: AsyncConnection, device_id: str, start_time: datetime, end_time: datetime + ): + async with conn.cursor() as cur: + await cur.execute( + "DELETE FROM scada.scada_data WHERE device_id = %s AND time >= %s AND time <= %s", + (device_id, start_time, end_time), + ) diff --git a/app/infra/db/timescaledb/repositories/scheme.py b/app/infra/db/timescaledb/repositories/scheme.py new file mode 100644 index 0000000..bfa09ca --- /dev/null +++ b/app/infra/db/timescaledb/repositories/scheme.py @@ -0,0 +1,760 @@ +from typing import List, Any, Dict +from datetime import datetime, timedelta, timezone +from collections import defaultdict +from psycopg import AsyncConnection, Connection, sql +import app.services.globals as globals + +# 定义UTC+8时区 +UTC_8 = timezone(timedelta(hours=8)) + + +class SchemeRepository: + + # --- Link Simulation --- + + @staticmethod + async def insert_links_batch(conn: AsyncConnection, data: List[dict]): + """Batch insert for scheme.link_simulation using DELETE then COPY for performance.""" + if not data: + return + + # 获取批次中所有不同的时间点 + all_times = list(set(item["time"] for item in data)) + target_scheme_type = data[0]["scheme_type"] + target_scheme_name = data[0]["scheme_name"] + + # 使用事务确保原子性 + async with conn.transaction(): + async with conn.cursor() as cur: + # 1. 删除该批次涉及的所有时间点、scheme_type、scheme_name 的旧数据 + await cur.execute( + "DELETE FROM scheme.link_simulation WHERE time = ANY(%s) AND scheme_type = %s AND scheme_name = %s", + (all_times, target_scheme_type, target_scheme_name), + ) + + # 2. 使用 COPY 快速写入新数据 + async with cur.copy( + "COPY scheme.link_simulation (time, scheme_type, scheme_name, id, flow, friction, headloss, quality, reaction, setting, status, velocity) FROM STDIN" + ) as copy: + for item in data: + await copy.write_row( + ( + item["time"], + item["scheme_type"], + item["scheme_name"], + item["id"], + item.get("flow"), + item.get("friction"), + item.get("headloss"), + item.get("quality"), + item.get("reaction"), + item.get("setting"), + item.get("status"), + item.get("velocity"), + ) + ) + + @staticmethod + def insert_links_batch_sync(conn: Connection, data: List[dict]): + """Batch insert for scheme.link_simulation using DELETE then COPY for performance (sync version).""" + if not data: + return + + # 获取批次中所有不同的时间点 + all_times = list(set(item["time"] for item in data)) + target_scheme_type = data[0]["scheme_type"] + target_scheme_name = data[0]["scheme_name"] + + # 使用事务确保原子性 + with conn.transaction(): + with conn.cursor() as cur: + # 1. 删除该批次涉及的所有时间点、scheme_type、scheme_name 的旧数据 + cur.execute( + "DELETE FROM scheme.link_simulation WHERE time = ANY(%s) AND scheme_type = %s AND scheme_name = %s", + (all_times, target_scheme_type, target_scheme_name), + ) + + # 2. 使用 COPY 快速写入新数据 + with cur.copy( + "COPY scheme.link_simulation (time, scheme_type, scheme_name, id, flow, friction, headloss, quality, reaction, setting, status, velocity) FROM STDIN" + ) as copy: + for item in data: + copy.write_row( + ( + item["time"], + item["scheme_type"], + item["scheme_name"], + item["id"], + item.get("flow"), + item.get("friction"), + item.get("headloss"), + item.get("quality"), + item.get("reaction"), + item.get("setting"), + item.get("status"), + item.get("velocity"), + ) + ) + + @staticmethod + async def get_link_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + link_id: str, + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM scheme.link_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s AND id = %s", + (scheme_type, scheme_name, start_time, end_time, link_id), + ) + return await cur.fetchall() + + @staticmethod + async def get_links_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM scheme.link_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s", + (scheme_type, scheme_name, start_time, end_time), + ) + return await cur.fetchall() + + @staticmethod + async def get_link_field_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + link_id: str, + field: str, + ) -> List[Dict[str, Any]]: + # Validate field name to prevent SQL injection + valid_fields = { + "flow", + "friction", + "headloss", + "quality", + "reaction", + "setting", + "status", + "velocity", + } + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT time, {} FROM scheme.link_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute( + query, (scheme_type, scheme_name, start_time, end_time, link_id) + ) + rows = await cur.fetchall() + return [ + {"time": row["time"].isoformat(), "value": row[field]} for row in rows + ] + + @staticmethod + async def get_links_field_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + field: str, + ) -> dict: + # Validate field name to prevent SQL injection + valid_fields = { + "flow", + "friction", + "headloss", + "quality", + "reaction", + "setting", + "status", + "velocity", + } + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT id, time, {} FROM scheme.link_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (scheme_type, scheme_name, start_time, end_time)) + rows = await cur.fetchall() + result = defaultdict(list) + for row in rows: + result[row["id"]].append( + {"time": row["time"].isoformat(), "value": row[field]} + ) + return dict(result) + + @staticmethod + async def update_link_field( + conn: AsyncConnection, + time: datetime, + scheme_type: str, + scheme_name: str, + link_id: str, + field: str, + value: Any, + ): + valid_fields = { + "flow", + "friction", + "headloss", + "quality", + "reaction", + "setting", + "status", + "velocity", + } + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "UPDATE scheme.link_simulation SET {} = %s WHERE time = %s AND scheme_type = %s AND scheme_name = %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (value, time, scheme_type, scheme_name, link_id)) + + @staticmethod + async def delete_links_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + ): + async with conn.cursor() as cur: + await cur.execute( + "DELETE FROM scheme.link_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s", + (scheme_type, scheme_name, start_time, end_time), + ) + + # --- Node Simulation --- + + @staticmethod + async def insert_nodes_batch(conn: AsyncConnection, data: List[dict]): + if not data: + return + + # 获取批次中所有不同的时间点 + all_times = list(set(item["time"] for item in data)) + target_scheme_type = data[0]["scheme_type"] + target_scheme_name = data[0]["scheme_name"] + + # 使用事务确保原子性 + async with conn.transaction(): + async with conn.cursor() as cur: + # 1. 删除该批次涉及的所有时间点、scheme_type、scheme_name 的旧数据 + await cur.execute( + "DELETE FROM scheme.node_simulation WHERE time = ANY(%s) AND scheme_type = %s AND scheme_name = %s", + (all_times, target_scheme_type, target_scheme_name), + ) + + # 2. 使用 COPY 快速写入新数据 + async with cur.copy( + "COPY scheme.node_simulation (time, scheme_type, scheme_name, id, actual_demand, total_head, pressure, quality) FROM STDIN" + ) as copy: + for item in data: + await copy.write_row( + ( + item["time"], + item["scheme_type"], + item["scheme_name"], + item["id"], + item.get("actual_demand"), + item.get("total_head"), + item.get("pressure"), + item.get("quality"), + ) + ) + + @staticmethod + def insert_nodes_batch_sync(conn: Connection, data: List[dict]): + if not data: + return + + # 获取批次中所有不同的时间点 + all_times = list(set(item["time"] for item in data)) + target_scheme_type = data[0]["scheme_type"] + target_scheme_name = data[0]["scheme_name"] + + # 使用事务确保原子性 + with conn.transaction(): + with conn.cursor() as cur: + # 1. 删除该批次涉及的所有时间点、scheme_type、scheme_name 的旧数据 + cur.execute( + "DELETE FROM scheme.node_simulation WHERE time = ANY(%s) AND scheme_type = %s AND scheme_name = %s", + (all_times, target_scheme_type, target_scheme_name), + ) + + # 2. 使用 COPY 快速写入新数据 + with cur.copy( + "COPY scheme.node_simulation (time, scheme_type, scheme_name, id, actual_demand, total_head, pressure, quality) FROM STDIN" + ) as copy: + for item in data: + copy.write_row( + ( + item["time"], + item["scheme_type"], + item["scheme_name"], + item["id"], + item.get("actual_demand"), + item.get("total_head"), + item.get("pressure"), + item.get("quality"), + ) + ) + + @staticmethod + async def get_node_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + node_id: str, + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM scheme.node_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s AND id = %s", + (scheme_type, scheme_name, start_time, end_time, node_id), + ) + return await cur.fetchall() + + @staticmethod + async def get_nodes_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + ) -> List[dict]: + async with conn.cursor() as cur: + await cur.execute( + "SELECT * FROM scheme.node_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s", + (scheme_type, scheme_name, start_time, end_time), + ) + return await cur.fetchall() + + @staticmethod + async def get_node_field_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + node_id: str, + field: str, + ) -> List[Dict[str, Any]]: + # Validate field name to prevent SQL injection + valid_fields = {"actual_demand", "total_head", "pressure", "quality"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT time, {} FROM scheme.node_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute( + query, (scheme_type, scheme_name, start_time, end_time, node_id) + ) + rows = await cur.fetchall() + return [ + {"time": row["time"].isoformat(), "value": row[field]} for row in rows + ] + + @staticmethod + async def get_nodes_field_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + field: str, + ) -> dict: + # Validate field name to prevent SQL injection + valid_fields = {"actual_demand", "total_head", "pressure", "quality"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "SELECT id, time, {} FROM scheme.node_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (scheme_type, scheme_name, start_time, end_time)) + rows = await cur.fetchall() + result = defaultdict(list) + for row in rows: + result[row["id"]].append( + {"time": row["time"].isoformat(), "value": row[field]} + ) + return dict(result) + + @staticmethod + async def update_node_field( + conn: AsyncConnection, + time: datetime, + scheme_type: str, + scheme_name: str, + node_id: str, + field: str, + value: Any, + ): + valid_fields = {"actual_demand", "total_head", "pressure", "quality"} + if field not in valid_fields: + raise ValueError(f"Invalid field: {field}") + + query = sql.SQL( + "UPDATE scheme.node_simulation SET {} = %s WHERE time = %s AND scheme_type = %s AND scheme_name = %s AND id = %s" + ).format(sql.Identifier(field)) + + async with conn.cursor() as cur: + await cur.execute(query, (value, time, scheme_type, scheme_name, node_id)) + + @staticmethod + async def delete_nodes_by_scheme_and_time_range( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + start_time: datetime, + end_time: datetime, + ): + async with conn.cursor() as cur: + await cur.execute( + "DELETE FROM scheme.node_simulation WHERE scheme_type = %s AND scheme_name = %s AND time >= %s AND time <= %s", + (scheme_type, scheme_name, start_time, end_time), + ) + + # --- 复合查询 --- + + @staticmethod + async def store_scheme_simulation_result( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + node_result_list: List[Dict[str, any]], + link_result_list: List[Dict[str, any]], + result_start_time: str, + num_periods: int = 1, + ): + """ + Store scheme simulation results to TimescaleDB. + + Args: + conn: Database connection + scheme_type: Scheme type + scheme_name: Scheme name + node_result_list: List of node simulation results + link_result_list: List of link simulation results + result_start_time: Start time for the results (ISO format string) + """ + # Convert result_start_time string to datetime if needed + if isinstance(result_start_time, str): + # 如果是ISO格式字符串,解析并转换为UTC+8 + if result_start_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat( + result_start_time.replace("Z", "+00:00") + ) + simulation_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + simulation_time = datetime.fromisoformat(result_start_time) + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + else: + simulation_time = result_start_time + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + + timestep_parts = globals.hydraulic_timestep.split(":") + timestep = timedelta( + hours=int(timestep_parts[0]), + minutes=int(timestep_parts[1]), + seconds=int(timestep_parts[2]), + ) + + # Prepare node data for batch insert + node_data = [] + for node_result in node_result_list: + node_id = node_result.get("node") + for period_index in range(num_periods): + current_time = simulation_time + (timestep * period_index) + data = node_result.get("result", [])[period_index] + node_data.append( + { + "time": current_time, + "scheme_type": scheme_type, + "scheme_name": scheme_name, + "id": node_id, + "actual_demand": data.get("demand"), + "total_head": data.get("head"), + "pressure": data.get("pressure"), + "quality": data.get("quality"), + } + ) + + # Prepare link data for batch insert + link_data = [] + for link_result in link_result_list: + link_id = link_result.get("link") + for period_index in range(num_periods): + current_time = simulation_time + (timestep * period_index) + data = link_result.get("result", [])[period_index] + link_data.append( + { + "time": current_time, + "scheme_type": scheme_type, + "scheme_name": scheme_name, + "id": link_id, + "flow": data.get("flow"), + "friction": data.get("friction"), + "headloss": data.get("headloss"), + "quality": data.get("quality"), + "reaction": data.get("reaction"), + "setting": data.get("setting"), + "status": data.get("status"), + "velocity": data.get("velocity"), + } + ) + + # Insert data using batch methods + if node_data: + await SchemeRepository.insert_nodes_batch(conn, node_data) + + if link_data: + await SchemeRepository.insert_links_batch(conn, link_data) + + @staticmethod + def store_scheme_simulation_result_sync( + conn: Connection, + scheme_type: str, + scheme_name: str, + node_result_list: List[Dict[str, any]], + link_result_list: List[Dict[str, any]], + result_start_time: str, + num_periods: int = 1, + ): + """ + Store scheme simulation results to TimescaleDB (sync version). + + Args: + conn: Database connection + scheme_type: Scheme type + scheme_name: Scheme name + node_result_list: List of node simulation results + link_result_list: List of link simulation results + result_start_time: Start time for the results (ISO format string) + """ + # Convert result_start_time string to datetime if needed + if isinstance(result_start_time, str): + # 如果是ISO格式字符串,解析并转换为UTC+8 + if result_start_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat( + result_start_time.replace("Z", "+00:00") + ) + simulation_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + simulation_time = datetime.fromisoformat(result_start_time) + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + else: + simulation_time = result_start_time + if simulation_time.tzinfo is None: + simulation_time = simulation_time.replace(tzinfo=UTC_8) + + timestep_parts = globals.hydraulic_timestep.split(":") + timestep = timedelta( + hours=int(timestep_parts[0]), + minutes=int(timestep_parts[1]), + seconds=int(timestep_parts[2]), + ) + + # Prepare node data for batch insert + node_data = [] + for node_result in node_result_list: + node_id = node_result.get("node") + for period_index in range(num_periods): + current_time = simulation_time + (timestep * period_index) + data = node_result.get("result", [])[period_index] + node_data.append( + { + "time": current_time, + "scheme_type": scheme_type, + "scheme_name": scheme_name, + "id": node_id, + "actual_demand": data.get("demand"), + "total_head": data.get("head"), + "pressure": data.get("pressure"), + "quality": data.get("quality"), + } + ) + + # Prepare link data for batch insert + link_data = [] + for link_result in link_result_list: + link_id = link_result.get("link") + for period_index in range(num_periods): + current_time = simulation_time + (timestep * period_index) + data = link_result.get("result", [])[period_index] + link_data.append( + { + "time": current_time, + "scheme_type": scheme_type, + "scheme_name": scheme_name, + "id": link_id, + "flow": data.get("flow"), + "friction": data.get("friction"), + "headloss": data.get("headloss"), + "quality": data.get("quality"), + "reaction": data.get("reaction"), + "setting": data.get("setting"), + "status": data.get("status"), + "velocity": data.get("velocity"), + } + ) + + # Insert data using batch methods + if node_data: + SchemeRepository.insert_nodes_batch_sync(conn, node_data) + + if link_data: + SchemeRepository.insert_links_batch_sync(conn, link_data) + + @staticmethod + async def query_all_record_by_scheme_time_property( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + query_time: str, + type: str, + property: str, + ) -> list: + """ + Query all records by scheme, time and property from TimescaleDB. + + Args: + conn: Database connection + scheme_type: Scheme type + scheme_name: Scheme name + query_time: Time to query (ISO format string) + type: Type of data ("node" or "link") + property: Property/field to query + + Returns: + List of records matching the criteria + """ + # Convert query_time string to datetime + if isinstance(query_time, str): + if query_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat(query_time.replace("Z", "+00:00")) + target_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + target_time = datetime.fromisoformat(query_time) + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + else: + target_time = query_time + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + + # Create time range: query_time ± 1 second + start_time = target_time - timedelta(seconds=1) + end_time = target_time + timedelta(seconds=1) + + # Query based on type + if type.lower() == "node": + data = await SchemeRepository.get_nodes_field_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time, property + ) + elif type.lower() == "link": + data = await SchemeRepository.get_links_field_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time, property + ) + else: + raise ValueError(f"Invalid type: {type}. Must be 'node' or 'link'") + + # Format the results + # Format the results + result = [] + for id, items in data.items(): + for item in items: + result.append({"ID": id, "value": item["value"]}) + return result + + @staticmethod + async def query_scheme_simulation_result_by_id_time( + conn: AsyncConnection, + scheme_type: str, + scheme_name: str, + id: str, + type: str, + query_time: str, + ) -> list[dict]: + """ + Query scheme simulation results by id and time from TimescaleDB. + + Args: + conn: Database connection + scheme_type: Scheme type + scheme_name: Scheme name + id: The id of the node or link + type: Type of data ("node" or "link") + query_time: Time to query (ISO format string) + + Returns: + List of records matching the criteria + """ + # Convert query_time string to datetime + if isinstance(query_time, str): + if query_time.endswith("Z"): + # UTC时间,转换为UTC+8 + utc_time = datetime.fromisoformat(query_time.replace("Z", "+00:00")) + target_time = utc_time.astimezone(UTC_8) + else: + # 假设已经是UTC+8时间 + target_time = datetime.fromisoformat(query_time) + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + else: + target_time = query_time + if target_time.tzinfo is None: + target_time = target_time.replace(tzinfo=UTC_8) + + # Create time range: query_time ± 1 second + start_time = target_time - timedelta(seconds=1) + end_time = target_time + timedelta(seconds=1) + + # Query based on type + if type.lower() == "node": + return await SchemeRepository.get_node_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time, id + ) + elif type.lower() == "link": + return await SchemeRepository.get_link_by_scheme_and_time_range( + conn, scheme_type, scheme_name, start_time, end_time, id + ) + else: + raise ValueError(f"Invalid type: {type}. Must be 'node' or 'link'") diff --git a/postgresql_info.py b/app/infra/db/timescaledb/timescaledb_info.py similarity index 73% rename from postgresql_info.py rename to app/infra/db/timescaledb/timescaledb_info.py index be5b0c4..3a1fbd8 100644 --- a/postgresql_info.py +++ b/app/infra/db/timescaledb/timescaledb_info.py @@ -3,11 +3,11 @@ import os load_dotenv() -pg_name = os.getenv("DB_NAME") -pg_host = os.getenv("DB_HOST") -pg_port = os.getenv("DB_PORT") -pg_user = os.getenv("DB_USER") -pg_password = os.getenv("DB_PASSWORD") +pg_name = os.getenv("TIMESCALEDB_DB_NAME") +pg_host = os.getenv("TIMESCALEDB_DB_HOST") +pg_port = os.getenv("TIMESCALEDB_DB_PORT") +pg_user = os.getenv("TIMESCALEDB_DB_USER") +pg_password = os.getenv("TIMESCALEDB_DB_PASSWORD") def get_pgconn_string( diff --git a/epanet/__init__.py b/app/infra/epanet/__init__.py similarity index 100% rename from epanet/__init__.py rename to app/infra/epanet/__init__.py diff --git a/app/infra/epanet/epanet.py b/app/infra/epanet/epanet.py new file mode 100644 index 0000000..8283190 --- /dev/null +++ b/app/infra/epanet/epanet.py @@ -0,0 +1,451 @@ +import ctypes +import platform +import os +import sys +import json +import base64 +from datetime import datetime +import subprocess +import logging +from typing import Any + +sys.path.append("..") +from app.native.wndb import project +from app.native.wndb import inp_out + + +def _verify_platform(): + _platform = platform.system() + if _platform not in ["Windows", "Linux"]: + raise Exception(f"Platform {_platform} unsupported (not yet)") + + +if __name__ == "__main__": + _verify_platform() + + +class Output: + def __init__(self, path: str) -> None: + self._path = path + + if platform.system() == "Windows": + self._lib = ctypes.CDLL( + os.path.join(os.path.dirname(__file__), "windows", "epanet-output.dll") + ) + else: + self._lib = ctypes.CDLL( + os.path.join(os.path.dirname(__file__), "linux", "libepanet-output.so") + ) + + self._handle = ctypes.c_void_p() + self._check(self._lib.ENR_init(ctypes.byref(self._handle))) + + self._check( + self._lib.ENR_open(self._handle, ctypes.c_char_p(self._path.encode())) + ) + + def __del__(self): + # throw exception in destructor ? :) + self._check(self._lib.ENR_close(ctypes.byref(self._handle))) + + def _check(self, result): + if result != 0 and result != 10: + msg = ctypes.c_char_p() + code = self._lib.ENR_checkError(self._handle, ctypes.byref(msg)) + assert code == result + + error = f"Failed to read project [{self._path}] output, message [{msg.value.decode()}]" + + self._lib.ENR_free(ctypes.byref(msg)) + + raise Exception(error) + + def version(self) -> int: + v = ctypes.c_int() + self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) + return v.value + + def net_size(self) -> dict[str, int]: + element_count = ctypes.POINTER(ctypes.c_int)() + length = ctypes.c_int() + self._check( + self._lib.ENR_getNetSize( + self._handle, ctypes.byref(element_count), ctypes.byref(length) + ) + ) + assert length.value == 5 + category = ["node", "tank", "link", "pump", "valve"] + sizes = {} + for i in range(length.value): + sizes[category[i]] = element_count[i] + self._lib.ENR_free(ctypes.byref(element_count)) + return sizes + + def units(self) -> dict[str, str]: + f_us = ["CFS", "GPM", "MGD", "IMGD", "AFD", "LPS", "LPM", "MLD", "CMH", "CMD"] + p_us = ["PSI", "MTR", "KPA"] + q_us = ["NONE", "MGL", "UGL", "HOURS", "PRCNT"] + f, p, q = ctypes.c_int(1), ctypes.c_int(2), ctypes.c_int(3) + f_u, p_u, q_u = ctypes.c_int(), ctypes.c_int(), ctypes.c_int() + self._check(self._lib.ENR_getUnits(self._handle, f, ctypes.byref(f_u))) + self._check(self._lib.ENR_getUnits(self._handle, p, ctypes.byref(p_u))) + self._check(self._lib.ENR_getUnits(self._handle, q, ctypes.byref(q_u))) + return { + "flow": f_us[f_u.value], + "pressure": p_us[p_u.value], + "quality": q_us[q_u.value], + } + + def times(self) -> dict[str, int]: + ts = [] + for i in range(1, 5): + t = ctypes.c_int(1) + self._check( + self._lib.ENR_getTimes(self._handle, ctypes.c_int(i), ctypes.byref(t)) + ) + ts.append(t.value) + d = {} + category = ["report_start", "report_step", "sim_duration", "num_periods"] + for i in range(4): + d[category[i]] = ts[i] + return d + + def element_name(self) -> dict[str, list[str]]: + sizes = self.net_size() + + node_type = ctypes.c_int(1) + nodes = [] + for i in range(1, sizes["node"] + 1): + name = ctypes.c_char_p() + name_len = ctypes.c_int() + self._check( + self._lib.ENR_getElementName( + self._handle, + node_type, + ctypes.c_int(i), + ctypes.byref(name), + ctypes.byref(name_len), + ) + ) + nodes.append(name.value.decode()) + self._lib.ENR_free(ctypes.byref(name)) + + link_type = ctypes.c_int(2) + links = [] + for i in range(1, sizes["link"] + 1): + name = ctypes.c_char_p() + name_len = ctypes.c_int() + self._check( + self._lib.ENR_getElementName( + self._handle, + link_type, + ctypes.c_int(i), + ctypes.byref(name), + ctypes.byref(name_len), + ) + ) + links.append(name.value.decode()) + self._lib.ENR_free(ctypes.byref(name)) + + return {"nodes": nodes, "links": links} + + def energy_usage(self) -> list[dict[str, Any]]: + size = self.net_size()["pump"] + usages = [] + category = [ + "utilization", + "avg.efficiency", + "avg.kW/flow", + "avg.kwatts", + "max.kwatts", + "cost/day", + ] + links = self.element_name()["links"] + for i in range(1, size + 1): + index = ctypes.c_int() + values = ctypes.POINTER(ctypes.c_float)() + length = ctypes.c_int() + self._check( + self._lib.ENR_getEnergyUsage( + self._handle, + ctypes.c_int(i), + ctypes.byref(index), + ctypes.byref(values), + ctypes.byref(length), + ) + ) + assert length.value == 6 + d = {"pump": links[index.value - 1]} + for j in range(length.value): + d |= {category[j]: values[j]} + usages.append(d) + self._lib.ENR_free(ctypes.byref(values)) + return usages + + def reactions(self) -> dict[str, float]: + values = ctypes.POINTER(ctypes.c_float)() + length = ctypes.c_int() + self._check( + self._lib.ENR_getNetReacts( + self._handle, ctypes.byref(values), ctypes.byref(length) + ) + ) + assert length.value == 4 + category = ["bulk", "wall", "tank", "source"] + d = {} + for i in range(4): + d[category[i]] = values[i] + self._lib.ENR_free(ctypes.byref(values)) + return d + + def node_results(self) -> list[dict[str, Any]]: + size = self.net_size()["node"] + num_periods = self.times()["num_periods"] + nodes = self.element_name()["nodes"] + category = ["demand", "head", "pressure", "quality"] + ds = [] + for i in range(1, size + 1): + d = {"node": nodes[i - 1], "result": []} + for j in range(num_periods): + values = ctypes.POINTER(ctypes.c_float)() + length = ctypes.c_int() + self._check( + self._lib.ENR_getNodeResult( + self._handle, j, i, ctypes.byref(values), ctypes.byref(length) + ) + ) + assert length.value == len(category) + attributes = {} + for k in range(length.value): + attributes[category[k]] = values[k] + d["result"].append(attributes) + self._lib.ENR_free(ctypes.byref(values)) + ds.append(d) + return ds + + def link_results(self) -> list[dict[str, Any]]: + size = self.net_size()["link"] + num_periods = self.times()["num_periods"] + links = self.element_name()["links"] + category = [ + "flow", + "velocity", + "headloss", + "quality", + "status", + "setting", + "reaction", + "friction", + ] + ds = [] + + for i in range(1, size + 1): + d = {"link": links[i - 1], "result": []} + for j in range(num_periods): + values = ctypes.POINTER(ctypes.c_float)() + length = ctypes.c_int() + self._check( + self._lib.ENR_getLinkResult( + self._handle, j, i, ctypes.byref(values), ctypes.byref(length) + ) + ) + assert length.value == len(category) + attributes = {} + for k in range(length.value): + if category[k] == "status": + if values[k] == 2.0: + attributes[category[k]] = "CLOSED" + else: + attributes[category[k]] = "OPEN" + continue + attributes[category[k]] = values[k] + d["result"].append(attributes) + self._lib.ENR_free(ctypes.byref(values)) + ds.append(d) + return ds + + def dump(self) -> dict[str, Any]: + data = {} + data |= {"version": self.version()} + data |= {"net_size": self.net_size()} + data |= {"units": self.units()} + data |= {"times": self.times()} + data |= {"element_name": self.element_name()} + data |= {"energy_usage": self.energy_usage()} + data |= {"reactions": self.reactions()} + data |= {"node_results": self.node_results()} + data |= {"link_results": self.link_results()} + return data + + +def _dump_output(path: str) -> dict[str, Any]: + opt = Output(path) + data = opt.dump() + with open(path + ".json", "w") as f: + json.dump(data, f) + return data + + +def dump_output(path: str) -> str: + data = _dump_output(path) + return json.dumps(data) + + +def dump_report(path: str) -> str: + return open(path, "r").read() + + +def dump_output_binary(path: str) -> str: + with open(path, "rb") as f: + data = f.read() + bast64_data = base64.b64encode(data) + return str(bast64_data, "utf-8") + + +# DingZQ, 2025-02-04, 返回dict[str, Any] +def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: + if not project.have_project(name): + raise Exception(f"Not found project [{name}]") + + dir = os.path.abspath(os.getcwd()) + + db_inp = os.path.join(os.path.join(dir, "db_inp"), name + ".db.inp") + inp_out.dump_inp(name, db_inp, "2") + + input = name + ".db" + if platform.system() == "Windows": + exe = os.path.join(os.path.dirname(__file__), "windows", "runepanet.exe") + else: + exe = os.path.join(os.path.dirname(__file__), "linux", "runepanet") + inp = os.path.join(os.path.join(dir, "db_inp"), input + ".inp") + rpt = os.path.join(os.path.join(dir, "temp"), input + ".rpt") + opt = os.path.join(os.path.join(dir, "temp"), input + ".opt") + command = f"{exe} {inp} {rpt} {opt}" + + if platform.system() != "Windows": + if not os.access(exe, os.X_OK): + os.chmod(exe, 0o755) + + data = {} + + # 设置环境变量以包含库文件路径 + env = os.environ.copy() + if platform.system() == "Linux": + lib_dir = os.path.dirname(exe) + env["LD_LIBRARY_PATH"] = f"{lib_dir}:{env.get('LD_LIBRARY_PATH', '')}" + + # 使用 subprocess 替代 os.system 以传递 env + process = subprocess.run(command, shell=True, env=env) + result = process.returncode + + if result != 0: + data["simulation_result"] = "failed" + else: + data["simulation_result"] = "successful" + if readable_output: + data["output"] = _dump_output(opt) + else: + data["output"] = dump_output_binary(opt) + + data["report"] = dump_report(rpt) + + return data + + +# original code +def run_project(name: str, readable_output: bool = False) -> str: + if not project.have_project(name): + raise Exception(f"Not found project [{name}]") + + dir = os.path.abspath(os.getcwd()) + + db_inp = os.path.join(os.path.join(dir, "db_inp"), name + ".db.inp") + inp_out.dump_inp(name, db_inp, "2") + + input = name + ".db" + if platform.system() == "Windows": + exe = os.path.join(os.path.dirname(__file__), "windows", "runepanet.exe") + else: + exe = os.path.join(os.path.dirname(__file__), "linux", "runepanet") + inp = os.path.join(os.path.join(dir, "db_inp"), input + ".inp") + rpt = os.path.join(os.path.join(dir, "temp"), input + ".rpt") + opt = os.path.join(os.path.join(dir, "temp"), input + ".opt") + + command = f"{exe} {inp} {rpt} {opt}" + logging.info(f"Run simulation at {datetime.now()}") + logging.info(command) + + if platform.system() != "Windows": + if not os.access(exe, os.X_OK): + os.chmod(exe, 0o755) + + data = {} + + # 设置环境变量以包含库文件路径 + env = os.environ.copy() + if platform.system() == "Linux": + lib_dir = os.path.dirname(exe) + env["LD_LIBRARY_PATH"] = f"{lib_dir}:{env.get('LD_LIBRARY_PATH', '')}" + + # DingZQ, 2025-06-02, 使用subprocess替代os.system + process = subprocess.run(command, shell=True, env=env) + result = process.returncode + # logging.info(f"Simulation result: {result}") + + if result != 0: + data["simulation_result"] = "failed" + + logging.error("simulation failed") + + else: + data["simulation_result"] = "successful" + logging.info("simulation successful") + + if readable_output: + data |= _dump_output(opt) + else: + data["output"] = dump_output_binary(opt) + + data["report"] = dump_report(rpt) + # logging.info(f"Report: {data['report']}") + + return json.dumps(data) + + +def run_inp(name: str) -> str: + dir = os.path.abspath(os.getcwd()) + + if platform.system() == "Windows": + exe = os.path.join(os.path.dirname(__file__), "windows", "runepanet.exe") + else: + exe = os.path.join(os.path.dirname(__file__), "linux", "runepanet") + inp = os.path.join(os.path.join(dir, "inp"), name + ".inp") + rpt = os.path.join(os.path.join(dir, "temp"), name + ".rpt") + opt = os.path.join(os.path.join(dir, "temp"), name + ".opt") + command = f"{exe} {inp} {rpt} {opt}" + + if platform.system() != "Windows": + if not os.access(exe, os.X_OK): + os.chmod(exe, 0o755) + + data = {} + + # 设置环境变量以包含库文件路径 + env = os.environ.copy() + if platform.system() == "Linux": + lib_dir = os.path.dirname(exe) + env["LD_LIBRARY_PATH"] = f"{lib_dir}:{env.get('LD_LIBRARY_PATH', '')}" + + process = subprocess.run(command, shell=True, env=env) + result = process.returncode + + if result != 0: + data["simulation_result"] = "failed" + else: + data["simulation_result"] = "successful" + # data |= _dump_output(opt) + data["output"] = dump_output_binary(opt) + + data["report"] = dump_report(rpt) + + return json.dumps(data) diff --git a/app/infra/epanet/linux/libepanet-output.so b/app/infra/epanet/linux/libepanet-output.so new file mode 100644 index 0000000..537670d Binary files /dev/null and b/app/infra/epanet/linux/libepanet-output.so differ diff --git a/app/infra/epanet/linux/libepanet2.so b/app/infra/epanet/linux/libepanet2.so new file mode 100644 index 0000000..8e9d341 Binary files /dev/null and b/app/infra/epanet/linux/libepanet2.so differ diff --git a/app/infra/epanet/linux/runepanet b/app/infra/epanet/linux/runepanet new file mode 100755 index 0000000..7aa1e80 Binary files /dev/null and b/app/infra/epanet/linux/runepanet differ diff --git a/epanet/epanet-output.dll b/app/infra/epanet/windows/epanet-output.dll similarity index 100% rename from epanet/epanet-output.dll rename to app/infra/epanet/windows/epanet-output.dll diff --git a/epanet/epanet2.dll b/app/infra/epanet/windows/epanet2.dll similarity index 100% rename from epanet/epanet2.dll rename to app/infra/epanet/windows/epanet2.dll diff --git a/epanet/runepanet.exe b/app/infra/epanet/windows/runepanet.exe similarity index 100% rename from epanet/runepanet.exe rename to app/infra/epanet/windows/runepanet.exe diff --git a/app/infra/repositories/__init__.py b/app/infra/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/infra/repositories/audit_repository.py b/app/infra/repositories/audit_repository.py new file mode 100644 index 0000000..91af4fb --- /dev/null +++ b/app/infra/repositories/audit_repository.py @@ -0,0 +1,112 @@ +from datetime import datetime +from typing import Optional, List +from uuid import UUID + +from sqlalchemy import func, select +from sqlalchemy.ext.asyncio import AsyncSession + +from app.domain.schemas.audit import AuditLogResponse +from app.infra.db.metadata import models + + +class AuditRepository: + """审计日志数据访问层(system_hub)""" + + def __init__(self, session: AsyncSession): + self.session = session + + async def create_log( + self, + action: str, + user_id: Optional[UUID] = None, + project_id: Optional[UUID] = None, + resource_type: Optional[str] = None, + resource_id: Optional[str] = None, + ip_address: Optional[str] = None, + request_method: Optional[str] = None, + request_path: Optional[str] = None, + request_data: Optional[dict] = None, + response_status: Optional[int] = None, + ) -> AuditLogResponse: + log = models.AuditLog( + user_id=user_id, + project_id=project_id, + action=action, + resource_type=resource_type, + resource_id=resource_id, + ip_address=ip_address, + request_method=request_method, + request_path=request_path, + request_data=request_data, + response_status=response_status, + timestamp=datetime.utcnow(), + ) + self.session.add(log) + await self.session.commit() + await self.session.refresh(log) + return AuditLogResponse.model_validate(log) + + async def get_logs( + self, + user_id: Optional[UUID] = None, + project_id: Optional[UUID] = None, + action: Optional[str] = None, + resource_type: Optional[str] = None, + start_time: Optional[datetime] = None, + end_time: Optional[datetime] = None, + skip: int = 0, + limit: int = 100, + ) -> List[AuditLogResponse]: + conditions = [] + if user_id is not None: + conditions.append(models.AuditLog.user_id == user_id) + if project_id is not None: + conditions.append(models.AuditLog.project_id == project_id) + if action: + conditions.append(models.AuditLog.action == action) + if resource_type: + conditions.append(models.AuditLog.resource_type == resource_type) + if start_time: + conditions.append(models.AuditLog.timestamp >= start_time) + if end_time: + conditions.append(models.AuditLog.timestamp <= end_time) + + stmt = ( + select(models.AuditLog) + .where(*conditions) + .order_by(models.AuditLog.timestamp.desc()) + .offset(skip) + .limit(limit) + ) + result = await self.session.execute(stmt) + return [ + AuditLogResponse.model_validate(log) + for log in result.scalars().all() + ] + + async def get_log_count( + self, + user_id: Optional[UUID] = None, + project_id: Optional[UUID] = None, + action: Optional[str] = None, + resource_type: Optional[str] = None, + start_time: Optional[datetime] = None, + end_time: Optional[datetime] = None, + ) -> int: + conditions = [] + if user_id is not None: + conditions.append(models.AuditLog.user_id == user_id) + if project_id is not None: + conditions.append(models.AuditLog.project_id == project_id) + if action: + conditions.append(models.AuditLog.action == action) + if resource_type: + conditions.append(models.AuditLog.resource_type == resource_type) + if start_time: + conditions.append(models.AuditLog.timestamp >= start_time) + if end_time: + conditions.append(models.AuditLog.timestamp <= end_time) + + stmt = select(func.count()).select_from(models.AuditLog).where(*conditions) + result = await self.session.execute(stmt) + return int(result.scalar() or 0) diff --git a/app/infra/repositories/metadata_repository.py b/app/infra/repositories/metadata_repository.py new file mode 100644 index 0000000..b9c47b7 --- /dev/null +++ b/app/infra/repositories/metadata_repository.py @@ -0,0 +1,203 @@ +from dataclasses import dataclass +from typing import Optional, List +from uuid import UUID + +from cryptography.fernet import InvalidToken +from sqlalchemy import select +from sqlalchemy.ext.asyncio import AsyncSession + +from app.core.encryption import ( + get_database_encryptor, + get_encryptor, + is_database_encryption_configured, + is_encryption_configured, +) +from app.infra.db.metadata import models + + +def _normalize_postgres_dsn(dsn: str) -> str: + if not dsn or "://" not in dsn: + return dsn + scheme, rest = dsn.split("://", 1) + if scheme not in ("postgresql", "postgres", "postgresql+psycopg"): + return dsn + if "@" not in rest: + return dsn + userinfo, hostinfo = rest.rsplit("@", 1) + if ":" not in userinfo: + return dsn + username, password = userinfo.split(":", 1) + if "@" not in password: + return dsn + password = password.replace("@", "%40") + return f"{scheme}://{username}:{password}@{hostinfo}" + + +@dataclass(frozen=True) +class ProjectDbRouting: + project_id: UUID + db_role: str + db_type: str + dsn: str + pool_min_size: int + pool_max_size: int + + +@dataclass(frozen=True) +class ProjectGeoServerInfo: + project_id: UUID + gs_base_url: Optional[str] + gs_admin_user: Optional[str] + gs_admin_password: Optional[str] + gs_datastore_name: str + default_extent: Optional[dict] + srid: int + + +@dataclass(frozen=True) +class ProjectSummary: + project_id: UUID + name: str + code: str + description: Optional[str] + gs_workspace: str + status: str + project_role: str + + +class MetadataRepository: + """元数据访问层(system_hub)""" + + def __init__(self, session: AsyncSession): + self.session = session + + async def get_user_by_keycloak_id(self, keycloak_id: UUID) -> Optional[models.User]: + result = await self.session.execute( + select(models.User).where(models.User.keycloak_id == keycloak_id) + ) + return result.scalar_one_or_none() + + async def get_user_by_username(self, username: str) -> Optional[models.User]: + result = await self.session.execute( + select(models.User).where(models.User.username == username) + ) + return result.scalar_one_or_none() + + async def get_project_by_id(self, project_id: UUID) -> Optional[models.Project]: + result = await self.session.execute( + select(models.Project).where(models.Project.id == project_id) + ) + return result.scalar_one_or_none() + + async def get_membership_role( + self, project_id: UUID, user_id: UUID + ) -> Optional[str]: + result = await self.session.execute( + select(models.UserProjectMembership.project_role).where( + models.UserProjectMembership.project_id == project_id, + models.UserProjectMembership.user_id == user_id, + ) + ) + return result.scalar_one_or_none() + + async def get_project_db_routing( + self, project_id: UUID, db_role: str + ) -> Optional[ProjectDbRouting]: + result = await self.session.execute( + select(models.ProjectDatabase).where( + models.ProjectDatabase.project_id == project_id, + models.ProjectDatabase.db_role == db_role, + ) + ) + record = result.scalar_one_or_none() + if not record: + return None + if not is_database_encryption_configured(): + raise ValueError("DATABASE_ENCRYPTION_KEY is not configured") + encryptor = get_database_encryptor() + try: + dsn = encryptor.decrypt(record.dsn_encrypted) + except InvalidToken: + raise ValueError( + "Failed to decrypt project DB DSN: DATABASE_ENCRYPTION_KEY mismatch " + "or invalid dsn_encrypted value" + ) + dsn = _normalize_postgres_dsn(dsn) + return ProjectDbRouting( + project_id=record.project_id, + db_role=record.db_role, + db_type=record.db_type, + dsn=dsn, + pool_min_size=record.pool_min_size, + pool_max_size=record.pool_max_size, + ) + + async def get_geoserver_config( + self, project_id: UUID + ) -> Optional[ProjectGeoServerInfo]: + result = await self.session.execute( + select(models.ProjectGeoServerConfig).where( + models.ProjectGeoServerConfig.project_id == project_id + ) + ) + record = result.scalar_one_or_none() + if not record: + return None + if record.gs_admin_password_encrypted: + if is_encryption_configured(): + encryptor = get_encryptor() + password = encryptor.decrypt(record.gs_admin_password_encrypted) + else: + password = record.gs_admin_password_encrypted + else: + password = None + return ProjectGeoServerInfo( + project_id=record.project_id, + gs_base_url=record.gs_base_url, + gs_admin_user=record.gs_admin_user, + gs_admin_password=password, + gs_datastore_name=record.gs_datastore_name, + default_extent=record.default_extent, + srid=record.srid, + ) + + async def list_projects_for_user(self, user_id: UUID) -> List[ProjectSummary]: + stmt = ( + select(models.Project, models.UserProjectMembership.project_role) + .join( + models.UserProjectMembership, + models.UserProjectMembership.project_id == models.Project.id, + ) + .where(models.UserProjectMembership.user_id == user_id) + .order_by(models.Project.name) + ) + result = await self.session.execute(stmt) + return [ + ProjectSummary( + project_id=project.id, + name=project.name, + code=project.code, + description=project.description, + gs_workspace=project.gs_workspace, + status=project.status, + project_role=role, + ) + for project, role in result.all() + ] + + async def list_all_projects(self) -> List[ProjectSummary]: + result = await self.session.execute( + select(models.Project).order_by(models.Project.name) + ) + return [ + ProjectSummary( + project_id=project.id, + name=project.name, + code=project.code, + description=project.description, + gs_workspace=project.gs_workspace, + status=project.status, + project_role="owner", + ) + for project in result.scalars().all() + ] diff --git a/app/infra/repositories/user_repository.py b/app/infra/repositories/user_repository.py new file mode 100644 index 0000000..4d975ec --- /dev/null +++ b/app/infra/repositories/user_repository.py @@ -0,0 +1,235 @@ +from typing import Optional, List +from datetime import datetime +from app.infra.db.postgresql.database import Database +from app.domain.schemas.user import UserCreate, UserUpdate, UserInDB +from app.domain.models.role import UserRole +from app.core.security import get_password_hash +import logging + +logger = logging.getLogger(__name__) + +class UserRepository: + """用户数据访问层""" + + def __init__(self, db: Database): + self.db = db + + async def create_user(self, user: UserCreate) -> Optional[UserInDB]: + """ + 创建新用户 + + Args: + user: 用户创建数据 + + Returns: + 创建的用户对象 + """ + hashed_password = get_password_hash(user.password) + + query = """ + INSERT INTO users (username, email, hashed_password, role, is_active, is_superuser) + VALUES (%(username)s, %(email)s, %(hashed_password)s, %(role)s, TRUE, FALSE) + RETURNING id, username, email, hashed_password, role, is_active, is_superuser, + created_at, updated_at + """ + + try: + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, { + 'username': user.username, + 'email': user.email, + 'hashed_password': hashed_password, + 'role': user.role.value + }) + row = await cur.fetchone() + if row: + return UserInDB(**row) + except Exception as e: + logger.error(f"Error creating user: {e}") + raise + + return None + + async def get_user_by_id(self, user_id: int) -> Optional[UserInDB]: + """根据ID获取用户""" + query = """ + SELECT id, username, email, hashed_password, role, is_active, is_superuser, + created_at, updated_at + FROM users + WHERE id = %(user_id)s + """ + + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, {'user_id': user_id}) + row = await cur.fetchone() + if row: + return UserInDB(**row) + + return None + + async def get_user_by_username(self, username: str) -> Optional[UserInDB]: + """根据用户名获取用户""" + query = """ + SELECT id, username, email, hashed_password, role, is_active, is_superuser, + created_at, updated_at + FROM users + WHERE username = %(username)s + """ + + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, {'username': username}) + row = await cur.fetchone() + if row: + return UserInDB(**row) + + return None + + async def get_user_by_email(self, email: str) -> Optional[UserInDB]: + """根据邮箱获取用户""" + query = """ + SELECT id, username, email, hashed_password, role, is_active, is_superuser, + created_at, updated_at + FROM users + WHERE email = %(email)s + """ + + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, {'email': email}) + row = await cur.fetchone() + if row: + return UserInDB(**row) + + return None + + async def get_all_users(self, skip: int = 0, limit: int = 100) -> List[UserInDB]: + """获取所有用户(分页)""" + query = """ + SELECT id, username, email, hashed_password, role, is_active, is_superuser, + created_at, updated_at + FROM users + ORDER BY created_at DESC + LIMIT %(limit)s OFFSET %(skip)s + """ + + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, {'skip': skip, 'limit': limit}) + rows = await cur.fetchall() + return [UserInDB(**row) for row in rows] + + async def update_user(self, user_id: int, user_update: UserUpdate) -> Optional[UserInDB]: + """ + 更新用户信息 + + Args: + user_id: 用户ID + user_update: 更新数据 + + Returns: + 更新后的用户对象 + """ + # 构建动态更新语句 + update_fields = [] + params = {'user_id': user_id} + + if user_update.email is not None: + update_fields.append("email = %(email)s") + params['email'] = user_update.email + + if user_update.password is not None: + update_fields.append("hashed_password = %(hashed_password)s") + params['hashed_password'] = get_password_hash(user_update.password) + + if user_update.role is not None: + update_fields.append("role = %(role)s") + params['role'] = user_update.role.value + + if user_update.is_active is not None: + update_fields.append("is_active = %(is_active)s") + params['is_active'] = user_update.is_active + + if not update_fields: + return await self.get_user_by_id(user_id) + + query = f""" + UPDATE users + SET {', '.join(update_fields)}, updated_at = CURRENT_TIMESTAMP + WHERE id = %(user_id)s + RETURNING id, username, email, hashed_password, role, is_active, is_superuser, + created_at, updated_at + """ + + try: + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, params) + row = await cur.fetchone() + if row: + return UserInDB(**row) + except Exception as e: + logger.error(f"Error updating user {user_id}: {e}") + raise + + return None + + async def delete_user(self, user_id: int) -> bool: + """ + 删除用户 + + Args: + user_id: 用户ID + + Returns: + 是否成功删除 + """ + query = "DELETE FROM users WHERE id = %(user_id)s" + + try: + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, {'user_id': user_id}) + return cur.rowcount > 0 + except Exception as e: + logger.error(f"Error deleting user {user_id}: {e}") + return False + + async def user_exists(self, username: str = None, email: str = None) -> bool: + """ + 检查用户是否存在 + + Args: + username: 用户名 + email: 邮箱 + + Returns: + 是否存在 + """ + conditions = [] + params = {} + + if username: + conditions.append("username = %(username)s") + params['username'] = username + + if email: + conditions.append("email = %(email)s") + params['email'] = email + + if not conditions: + return False + + query = f""" + SELECT EXISTS( + SELECT 1 FROM users WHERE {' OR '.join(conditions)} + ) + """ + + async with self.db.get_connection() as conn: + async with conn.cursor() as cur: + await cur.execute(query, params) + result = await cur.fetchone() + return result['exists'] if result else False diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..947647c --- /dev/null +++ b/app/main.py @@ -0,0 +1,87 @@ +from fastapi import FastAPI +from contextlib import asynccontextmanager +from fastapi.middleware.gzip import GZipMiddleware +from fastapi.middleware.cors import CORSMiddleware +import logging +from datetime import datetime + +import app.services.project_info as project_info +from app.api.v1.router import api_router +from app.infra.db.timescaledb.database import db as tsdb +from app.infra.db.postgresql.database import db as pgdb +from app.infra.db.dynamic_manager import project_connection_manager +from app.infra.db.metadata.database import close_metadata_engine +from app.services.tjnetwork import open_project +from app.core.config import settings + +# 导入审计中间件 +from app.infra.audit.middleware import AuditMiddleware + + +logger = logging.getLogger() +logger.setLevel(logging.INFO) + + +@asynccontextmanager +async def lifespan(app: FastAPI): + logger.info("**********************************************************") + logger.info(str(datetime.now())) + logger.info("TJWater CloudService is starting...") + logger.info("**********************************************************") + + # 初始化数据库连接池 + tsdb.init_pool() + pgdb.init_pool() + + await tsdb.open() + await pgdb.open() + + # 将数据库实例存储到 app.state,供依赖项使用 + app.state.db = pgdb + logger.info("Database connection pool initialized and stored in app.state") + + if project_info.name: + print(project_info.name) + open_project(project_info.name) + + yield + # 清理资源 + await tsdb.close() + await pgdb.close() + await project_connection_manager.close_all() + await close_metadata_engine() + logger.info("Database connections closed") + + +# 根据环境配置决定是否启用文档 +is_production = settings.ENVIRONMENT.lower() == "production" + +app = FastAPI( + lifespan=lifespan, + title=settings.PROJECT_NAME, + description="TJWater Server - 供水管网智能管理系统", + version="1.0.0", + docs_url=None if is_production else "/docs", + redoc_url=None if is_production else "/redoc", + openapi_url=None if is_production else "/openapi.json", +) + + +# Include Routers +app.include_router(api_router, prefix="/api/v1") +# Legcy Routers without version prefix +app.include_router(api_router) + +# 配置中间件 +app.add_middleware(GZipMiddleware, minimum_size=1000) +# 添加审计中间件(可选,记录关键操作) +app.add_middleware(AuditMiddleware) +# 配置 CORS 中间件 +# 确保这是你最后一个添加的 app.add_middleware +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # 允许所有来源 + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) diff --git a/app/native/__init__.py b/app/native/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/native/wndb/__init__.py b/app/native/wndb/__init__.py new file mode 100644 index 0000000..8a5978b --- /dev/null +++ b/app/native/wndb/__init__.py @@ -0,0 +1,466 @@ +"""`app.native.wndb` 的公共 API 门面。 + +调用建议: +- 推荐使用模块方式导入,保持调用点清晰: + `import app.native.wndb as wndb` +- 典型流程: + 1) 项目生命周期:`open_project(...)` / `close_project(...)` + 2) 模型数据读写:`get_*`, `set_*`, `add_*`, `delete_*` + 3) 持久化与恢复:`take_snapshot(...)`, `execute_undo()`, `restore(...)` + +该文件刻意保持平铺导出,以兼容历史调用。 +""" + +# ----------------------------------------------------------------------------- +# 项目生命周期与 INP 导入导出 +# ----------------------------------------------------------------------------- +from .project import ( + list_project, + have_project, + create_project, + delete_project, + clean_project, +) +from .project import is_project_open, open_project, close_project +from .project import copy_project + +# DingZQ, 2024-12-28: 将 INP v3 转换为 v2 +from .inp_in import read_inp, import_inp, convert_inp_v3_to_v2 +from .inp_out import dump_inp, export_inp + +# ----------------------------------------------------------------------------- +# 数据库操作、快照与撤销重做 +# ----------------------------------------------------------------------------- +from .database import API_ADD, API_UPDATE, API_DELETE +from .database import ChangeSet +from .database import get_current_operation +from .database import execute_undo, execute_redo +from .database import list_snapshot +from .database import ( + have_snapshot, + have_snapshot_for_operation, + have_snapshot_for_current_operation, +) +from .database import ( + take_snapshot_for_operation, + take_snapshot_for_current_operation, + take_snapshot, +) +from .database import update_snapshot, update_snapshot_for_current_operation +from .database import delete_snapshot, delete_snapshot_by_operation +from .database import get_operation_by_snapshot, get_snapshot_by_operation +from .database import pick_snapshot +from .database import pick_operation, sync_with_server +from .database import ( + get_restore_operation, + set_restore_operation, + set_restore_operation_to_current, + restore, +) +from .database import read, try_read, read_all, write + +# ----------------------------------------------------------------------------- +# 批处理执行与扩展数据 +# ----------------------------------------------------------------------------- +from .batch_exe import execute_batch_commands, execute_batch_command + +from .extension_data import ( + get_all_extension_data_keys, + get_all_extension_data, + get_extension_data, + set_extension_data, +) + +# ----------------------------------------------------------------------------- +# 核心网络模型基础类型与辅助方法 +# ----------------------------------------------------------------------------- +from .s0_base import JUNCTION, RESERVOIR, TANK, PIPE, PUMP, VALVE, PATTERN, CURVE +from .s0_base import is_node, is_junction, is_reservoir, is_tank +from .s0_base import is_link, is_pipe, is_pump, is_valve +from .s0_base import is_curve +from .s0_base import is_pattern +from .s0_base import ( + get_nodes, + get_nodes_id_and_type, + get_junctions, + get_reservoirs, + get_tanks, + get_links, + get_links_id_and_type, + get_pipes, + get_pumps, + get_valves, + get_curves, + get_patterns, +) +from .s0_base import ( + get_node_type, + get_link_type, + get_element_type, + get_element_type_value, +) +from .s0_base import get_node_links, get_link_nodes +from .s0_base import get_major_nodes, get_major_pipes + +# ----------------------------------------------------------------------------- +# EPANET 基础分段(S1-S27) +# ----------------------------------------------------------------------------- +from .s1_title import get_title_schema, get_title, set_title + +from .s2_junctions import ( + get_junction_schema, + add_junction, + get_junction, + set_junction, + get_all_junctions, +) +from .batch_api import delete_junction_cascade + +from .s3_reservoirs import ( + get_reservoir_schema, + add_reservoir, + get_reservoir, + set_reservoir, + get_all_reservoirs, +) +from .batch_api import delete_reservoir_cascade + +from .s4_tanks import OVERFLOW_YES, OVERFLOW_NO +from .s4_tanks import get_tank_schema, add_tank, get_tank, set_tank, get_all_tanks +from .batch_api import delete_tank_cascade + +from .s5_pipes import PIPE_STATUS_OPEN, PIPE_STATUS_CLOSED, PIPE_STATUS_CV +from .s5_pipes import get_pipe_schema, add_pipe, get_pipe, set_pipe, get_all_pipes +from .batch_api import delete_pipe_cascade + +from .s6_pumps import get_pump_schema, add_pump, get_pump, set_pump, get_all_pumps +from .batch_api import delete_pump_cascade + +from .s7_valves import ( + VALVES_TYPE_PRV, + VALVES_TYPE_PSV, + VALVES_TYPE_PBV, + VALVES_TYPE_FCV, + VALVES_TYPE_TCV, + VALVES_TYPE_GPV, +) +from .s7_valves import get_valve_schema, add_valve, get_valve, set_valve, get_all_valves +from .batch_api import delete_valve_cascade + +from .s8_tags import TAG_TYPE_NODE, TAG_TYPE_LINK +from .s8_tags import get_tag_schema, get_tags, get_tag, set_tag + +from .s9_demands import get_demand_schema, get_demand, set_demand + +from .s10_status import LINK_STATUS_OPEN, LINK_STATUS_CLOSED, LINK_STATUS_ACTIVE +from .s10_status import get_status_schema, get_status, set_status + +from .s11_patterns import get_pattern_schema, get_pattern, set_pattern, add_pattern +from .batch_api import delete_pattern_cascade + +from .s12_curves import ( + CURVE_TYPE_PUMP, + CURVE_TYPE_EFFICIENCY, + CURVE_TYPE_VOLUME, + CURVE_TYPE_HEADLOSS, +) +from .s12_curves import get_curve_schema, get_curve, set_curve, add_curve +from .batch_api import delete_curve_cascade + +from .s13_controls import get_control_schema, get_control, set_control + +from .s14_rules import get_rule_schema, get_rule, set_rule + +from .s15_energy import get_energy_schema, get_energy, set_energy +from .s15_energy import get_pump_energy_schema, get_pump_energy, set_pump_energy + +from .s16_emitters import get_emitter_schema, get_emitter, set_emitter + +from .s17_quality import get_quality_schema, get_quality, set_quality + +from .s18_sources import ( + SOURCE_TYPE_CONCEN, + SOURCE_TYPE_MASS, + SOURCE_TYPE_FLOWPACED, + SOURCE_TYPE_SETPOINT, +) +from .s18_sources import ( + get_source_schema, + get_source, + set_source, + add_source, + delete_source, +) + +from .s19_reactions import get_reaction_schema, get_reaction, set_reaction +from .s19_reactions import ( + get_pipe_reaction_schema, + get_pipe_reaction, + set_pipe_reaction, +) +from .s19_reactions import ( + get_tank_reaction_schema, + get_tank_reaction, + set_tank_reaction, +) + +from .s20_mixing import ( + MIXING_MODEL_MIXED, + MIXING_MODEL_2COMP, + MIXING_MODEL_FIFO, + MIXING_MODEL_LIFO, +) +from .s20_mixing import ( + get_mixing_schema, + get_mixing, + set_mixing, + add_mixing, + delete_mixing, +) + +from .s21_times import ( + TIME_STATISTIC_NONE, + TIME_STATISTIC_AVERAGED, + TIME_STATISTIC_MINIMUM, + TIME_STATISTIC_MAXIMUM, + TIME_STATISTIC_RANGE, +) +from .s21_times import get_time_schema, get_time, set_time + +from .s23_options_util import ( + OPTION_UNITS_CFS, + OPTION_UNITS_GPM, + OPTION_UNITS_MGD, + OPTION_UNITS_IMGD, + OPTION_UNITS_AFD, + OPTION_UNITS_LPS, + OPTION_UNITS_LPM, + OPTION_UNITS_MLD, + OPTION_UNITS_CMH, + OPTION_UNITS_CMD, +) +from .s23_options_util import ( + OPTION_PRESSURE_PSI, + OPTION_PRESSURE_KPA, + OPTION_PRESSURE_METERS, +) +from .s23_options_util import OPTION_HEADLOSS_HW, OPTION_HEADLOSS_DW, OPTION_HEADLOSS_CM +from .s23_options_util import OPTION_UNBALANCED_STOP, OPTION_UNBALANCED_CONTINUE +from .s23_options_util import OPTION_DEMAND_MODEL_DDA, OPTION_DEMAND_MODEL_PDA +from .s23_options_util import ( + OPTION_QUALITY_NONE, + OPTION_QUALITY_CHEMICAL, + OPTION_QUALITY_AGE, + OPTION_QUALITY_TRACE, +) +from .s23_options_util import get_option_schema, get_option +from .batch_api import set_option_ex + +from .s23_options_util import ( + OPTION_V3_FLOW_UNITS_CFS, + OPTION_V3_FLOW_UNITS_GPM, + OPTION_V3_FLOW_UNITS_MGD, + OPTION_V3_FLOW_UNITS_IMGD, + OPTION_V3_FLOW_UNITS_AFD, + OPTION_V3_FLOW_UNITS_LPS, + OPTION_V3_FLOW_UNITS_LPM, + OPTION_V3_FLOW_UNITS_MLD, + OPTION_V3_FLOW_UNITS_CMH, + OPTION_V3_FLOW_UNITS_CMD, +) +from .s23_options_util import ( + OPTION_V3_PRESSURE_UNITS_PSI, + OPTION_V3_PRESSURE_UNITS_KPA, + OPTION_V3_PRESSURE_UNITS_METERS, +) +from .s23_options_util import ( + OPTION_V3_HEADLOSS_MODEL_HW, + OPTION_V3_HEADLOSS_MODEL_DW, + OPTION_V3_HEADLOSS_MODEL_CM, +) +from .s23_options_util import ( + OPTION_V3_STEP_SIZING_FULL, + OPTION_V3_STEP_SIZING_RELAXATION, + OPTION_V3_STEP_SIZING_LINESEARCH, +) +from .s23_options_util import ( + OPTION_V3_IF_UNBALANCED_STOP, + OPTION_V3_IF_UNBALANCED_CONTINUE, +) +from .s23_options_util import ( + OPTION_V3_DEMAND_MODEL_FIXED, + OPTION_V3_DEMAND_MODEL_CONSTRAINED, + OPTION_V3_DEMAND_MODEL_POWER, + OPTION_V3_DEMAND_MODEL_LOGISTIC, +) +from .s23_options_util import ( + OPTION_V3_LEAKAGE_MODEL_NONE, + OPTION_V3_LEAKAGE_MODEL_POWER, + OPTION_V3_LEAKAGE_MODEL_FAVAD, +) +from .s23_options_util import ( + OPTION_V3_QUALITY_MODEL_NONE, + OPTION_V3_QUALITY_MODEL_CHEMICAL, + OPTION_V3_QUALITY_MODEL_AGE, + OPTION_V3_QUALITY_MODEL_TRACE, +) +from .s23_options_util import ( + OPTION_V3_QUALITY_UNITS_HRS, + OPTION_V3_QUALITY_UNITS_PCNT, + OPTION_V3_QUALITY_UNITS_MGL, + OPTION_V3_QUALITY_UNITS_UGL, +) +from .s23_options_util import get_option_v3_schema, get_option_v3 +from .batch_api import set_option_v3_ex + +from .s24_coordinates import get_node_coord, get_nodes_in_extent, get_links_in_extent + +from .s25_vertices import ( + get_vertex_schema, + get_vertex, + set_vertex, + add_vertex, + delete_vertex, +) +from .s25_vertices import get_all_vertex_links, get_all_vertices + +from .s26_labels import get_label_schema, get_label, set_label, add_label, delete_label + +from .s27_backdrop import get_backdrop_schema, get_backdrop, set_backdrop + +# ----------------------------------------------------------------------------- +# SCADA 映射与遥测实体 +# ----------------------------------------------------------------------------- +from .s29_scada_device import ( + SCADA_DEVICE_TYPE_PRESSURE, + SCADA_DEVICE_TYPE_DEMAND, + SCADA_DEVICE_TYPE_QUALITY, + SCADA_DEVICE_TYPE_LEVEL, + SCADA_DEVICE_TYPE_FLOW, + SCADA_DEVICE_TYPE_UNKNOWN, +) +from .s29_scada_device import ( + get_scada_device_schema, + get_scada_device, + set_scada_device, + add_scada_device, + delete_scada_device, +) +from .s29_scada_device import get_all_scada_device_ids, get_all_scada_devices +from .clean_api import clean_scada_device + +from .s30_scada_device_data import ( + get_scada_device_data_schema, + get_scada_device_data, + set_scada_device_data, + add_scada_device_data, + delete_scada_device_data, +) +from .clean_api import clean_scada_device_data + +from .s31_scada_element import ( + SCADA_MODEL_TYPE_JUNCTION, + SCADA_MODEL_TYPE_RESERVOIR, + SCADA_MODEL_TYPE_TANK, + SCADA_MODEL_TYPE_PIPE, + SCADA_MODEL_TYPE_PUMP, + SCADA_MODEL_TYPE_VALVE, +) +from .s31_scada_element import SCADA_ELEMENT_STATUS_OFFLINE, SCADA_ELEMENT_STATUS_ONLINE +from .s31_scada_element import ( + get_scada_element_schema, + get_scada_element, + set_scada_element, + add_scada_element, + delete_scada_element, +) +from .s31_scada_element import get_all_scada_element_ids, get_all_scada_elements +from .clean_api import clean_scada_element + +# ----------------------------------------------------------------------------- +# 区域、DMA、服务分区、虚拟分区与需水分配 +# ----------------------------------------------------------------------------- +from .s32_region_util import ( + get_nodes_in_boundary, + get_nodes_in_region, + get_links_on_region_boundary, + calculate_convex_hull, + calculate_boundary, + inflate_boundary, + inflate_region, +) +from .s32_region import ( + get_region_schema, + get_region, + set_region, + add_region, + delete_region, +) + +from .s33_dma_cal import PARTITION_TYPE_RB, PARTITION_TYPE_KWAY +from .s33_dma_cal import ( + calculate_district_metering_area_for_nodes, + calculate_district_metering_area_for_region, + calculate_district_metering_area_for_network, +) +from .s33_dma import ( + get_district_metering_area_schema, + get_district_metering_area, + set_district_metering_area, + add_district_metering_area, + delete_district_metering_area, +) +from .s33_dma import get_all_district_metering_area_ids, get_all_district_metering_areas +from .s33_dma_gen import ( + generate_district_metering_area, + generate_sub_district_metering_area, +) + +from .s34_sa_cal import calculate_service_area +from .s34_sa import ( + get_service_area_schema, + get_service_area, + set_service_area, + add_service_area, + delete_service_area, +) +from .s34_sa import get_all_service_area_ids, get_all_service_areas +from .s34_sa_gen import generate_service_area + +from .s35_vd_cal import calculate_virtual_district +from .s35_vd import ( + get_virtual_district_schema, + get_virtual_district, + set_virtual_district, + add_virtual_district, + delete_virtual_district, +) +from .s35_vd import get_all_virtual_district_ids, get_all_virtual_districts +from .s35_vd_gen import generate_virtual_district + +from .s36_wda_cal import ( + calculate_demand_to_nodes, + calculate_demand_to_region, + calculate_demand_to_network, +) + +# ----------------------------------------------------------------------------- +# 元数据与高级分析 +# ----------------------------------------------------------------------------- +from .s38_scada_info import get_scada_info_schema, get_scada_info, get_all_scada_info + +from .s39_user import get_user_schema, get_user, get_all_users + +from .s40_schema import get_scheme_schema, get_scheme, get_all_schemes + +from .s41_pipe_risk_probability import ( + get_pipe_risk_probability_now, + get_pipe_risk_probability, + get_network_pipe_risk_probability_now, + get_pipes_risk_probability, + get_pipe_risk_probability_geometries, +) + +from .s42_sensor_placement import get_all_sensor_placements + +from .s43_burst_locate_result import get_all_burst_locate_results diff --git a/app/native/wndb/batch_api.py b/app/native/wndb/batch_api.py new file mode 100644 index 0000000..1c47d54 --- /dev/null +++ b/app/native/wndb/batch_api.py @@ -0,0 +1,53 @@ +from .sections import * +from .database import ChangeSet, API_DELETE, API_UPDATE +from .batch_exe import execute_batch_command + + +def delete_junction_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s2_junction } + return execute_batch_command(name, cs) + + +def delete_reservoir_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s3_reservoir } + return execute_batch_command(name, cs) + + +def delete_tank_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s4_tank } + return execute_batch_command(name, cs) + + +def delete_pipe_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s5_pipe } + return execute_batch_command(name, cs) + + +def delete_pump_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s6_pump } + return execute_batch_command(name, cs) + + +def delete_valve_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s7_valve } + return execute_batch_command(name, cs) + + +def delete_pattern_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s11_pattern } + return execute_batch_command(name, cs) + + +def delete_curve_cascade(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s12_curve } + return execute_batch_command(name, cs) + + +def set_option_ex(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_UPDATE, 'type' : s23_option } + return execute_batch_command(name, cs) + + +def set_option_v3_ex(name: str, cs: ChangeSet) -> ChangeSet: + cs.operations[0] |= { 'operation' : API_UPDATE, 'type' : s23_option_v3 } + return execute_batch_command(name, cs) diff --git a/app/native/wndb/batch_api_cs.py b/app/native/wndb/batch_api_cs.py new file mode 100644 index 0000000..ec94f53 --- /dev/null +++ b/app/native/wndb/batch_api_cs.py @@ -0,0 +1,238 @@ +from .database import ChangeSet, g_delete_prefix, API_DELETE, API_UPDATE, try_read +from .sections import * + +from .s0_base import * + +from .s3_reservoirs import unset_reservoir_by_pattern +from .s4_tanks import unset_tank_by_curve +from .s6_pumps import unset_pump_by_curve, unset_pump_by_pattern +from .s8_tags import delete_tag_by_node, delete_tag_by_link +from .s9_demands import delete_demand_by_junction, unset_demand_by_pattern +from .s10_status import delete_status_by_link +from .s15_energy import delete_pump_energy_by_pump, unset_pump_energy_by_pattern, unset_pump_energy_by_curve +from .s16_emitters import delete_emitter_by_junction +from .s17_quality import delete_quality_by_node +from .s18_sources import delete_source_by_node, unset_source_by_pattern +from .s19_reactions import delete_pipe_reaction_by_pipe, delete_tank_reaction_by_tank +from .s20_mixing import delete_mixing_by_tank +from .s25_vertices import delete_vertex_by_link +from .s26_labels import unset_label_by_node + +from .s23_options_util import generate_v2, generate_v3 + + +def delete_junction_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from junctions where id = '{id}'") + if row == None: + return result + + links = get_node_links(name, id) + + for link in links: + if is_pipe(name, link): + result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link}))) + if is_pump(name, link): + result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link}))) + if is_valve(name, link): + result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link}))) + + result.merge(delete_tag_by_node(name, id)) + result.merge(delete_demand_by_junction(name, id)) + result.merge(delete_emitter_by_junction(name, id)) + result.merge(delete_quality_by_node(name, id)) + result.merge(delete_source_by_node(name, id)) + result.merge(unset_label_by_node(name, id)) + result.merge(cs) + + return result + + +def delete_reservoir_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from reservoirs where id = '{id}'") + if row == None: + return result + + links = get_node_links(name, id) + + for link in links: + if is_pipe(name, link): + result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link}))) + if is_pump(name, link): + result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link}))) + if is_valve(name, link): + result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link}))) + + result.merge(delete_tag_by_node(name, id)) + result.merge(delete_quality_by_node(name, id)) + result.merge(delete_source_by_node(name, id)) + result.merge(unset_label_by_node(name, id)) + result.merge(cs) + + return result + + +def delete_tank_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from tanks where id = '{id}'") + if row == None: + return result + + links = get_node_links(name, id) + + for link in links: + if is_pipe(name, link): + result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link}))) + if is_pump(name, link): + result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link}))) + if is_valve(name, link): + result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link}))) + + result.merge(delete_tag_by_node(name, id)) + result.merge(delete_quality_by_node(name, id)) + result.merge(delete_source_by_node(name, id)) + result.merge(delete_tank_reaction_by_tank(name, id)) + result.merge(delete_mixing_by_tank(name, id)) + result.merge(unset_label_by_node(name, id)) + result.merge(cs) + + return result + + +def delete_pipe_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from pipes where id = '{id}'") + if row == None: + return result + + result.merge(delete_tag_by_link(name, id)) + result.merge(delete_status_by_link(name, id)) + result.merge(delete_pipe_reaction_by_pipe(name, id)) + result.merge(delete_vertex_by_link(name, id)) + result.merge(cs) + + return result + + +def delete_pump_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from pumps where id = '{id}'") + if row == None: + return result + + result.merge(delete_tag_by_link(name, id)) + result.merge(delete_status_by_link(name, id)) + result.merge(delete_pump_energy_by_pump(name, id)) + result.merge(delete_vertex_by_link(name, id)) + result.merge(cs) + + return result + + +def delete_valve_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from valves where id = '{id}'") + if row == None: + return result + + result.merge(delete_tag_by_link(name, id)) + result.merge(delete_status_by_link(name, id)) + result.merge(delete_vertex_by_link(name, id)) + + result.merge(cs) + + return result + + +def delete_pattern_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from _pattern where id = '{id}'") + if row == None: + return result + + result.merge(unset_reservoir_by_pattern(name, id)) + result.merge(unset_pump_by_pattern(name, id)) + result.merge(unset_demand_by_pattern(name, id)) + result.merge(unset_pump_energy_by_pattern(name, id)) + result.merge(unset_source_by_pattern(name, id)) + result.merge(cs) + + return result + + +def delete_curve_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet: + result = ChangeSet() + + id = cs.operations[0]['id'] + row = try_read(name, f"select * from _curve where id = '{id}'") + if row == None: + return result + + result.merge(unset_tank_by_curve(name, id)) + result.merge(unset_pump_by_curve(name, id)) + result.merge(unset_pump_energy_by_curve(name, id)) + result.merge(cs) + + return result + + +def set_option_cs(cs: ChangeSet) -> ChangeSet: + cs.operations[0]['operation'] = API_UPDATE + cs.operations[0]['type'] = 'option' + new_cs = cs + new_cs.merge(generate_v3(cs)) + return new_cs + + +def set_option_v3_cs(cs: ChangeSet) -> ChangeSet: + cs.operations[0]['operation'] = API_UPDATE + cs.operations[0]['type'] = 'option_v3' + new_cs = cs + new_cs.merge(generate_v2(cs)) + return new_cs + + +def rewrite_batch_api(name: str, cs: ChangeSet) -> ChangeSet: + op = cs.operations[0] + api = op['operation'] + type = op['type'] + + if api == API_DELETE: + if type == s2_junction: + return delete_junction_cascade_batch_cs(name, cs) + elif type == s3_reservoir: + return delete_reservoir_cascade_batch_cs(name, cs) + elif type == s4_tank: + return delete_tank_cascade_batch_cs(name, cs) + elif type == s5_pipe: + return delete_pipe_cascade_batch_cs(name, cs) + elif type == s6_pump: + return delete_pump_cascade_batch_cs(name, cs) + elif type == s7_valve: + return delete_valve_cascade_batch_cs(name, cs) + elif type == s11_pattern: + return delete_pattern_cascade_batch_cs(name, cs) + elif type == s12_curve: + return delete_curve_cascade_batch_cs(name, cs) + elif api == API_UPDATE: + if type == s23_option: + return set_option_cs(cs) + elif type == s23_option_v3: + return set_option_v3_cs(cs) + + return cs diff --git a/app/native/wndb/batch_exe.py b/app/native/wndb/batch_exe.py new file mode 100644 index 0000000..080688e --- /dev/null +++ b/app/native/wndb/batch_exe.py @@ -0,0 +1,380 @@ +from typing import Any +from .sections import * +from .database import API_ADD, API_UPDATE, API_DELETE, ChangeSet, write, read, read_all, get_current_operation +from .extension_data import set_extension_data +from .s1_title import set_title +from .s2_junctions import set_junction, add_junction, delete_junction +from .s3_reservoirs import set_reservoir, add_reservoir, delete_reservoir +from .s4_tanks import set_tank, add_tank, delete_tank +from .s5_pipes import set_pipe, add_pipe, delete_pipe +from .s6_pumps import set_pump, add_pump, delete_pump +from .s7_valves import set_valve, add_valve, delete_valve +from .s8_tags import set_tag +from .s9_demands import set_demand +from .s10_status import set_status +from .s11_patterns import set_pattern, add_pattern, delete_pattern +from .s12_curves import set_curve, add_curve, delete_curve +from .s13_controls import set_control +from .s14_rules import set_rule +from .s15_energy import set_energy, set_pump_energy +from .s16_emitters import set_emitter +from .s17_quality import set_quality +from .s18_sources import set_source, add_source, delete_source +from .s19_reactions import set_reaction, set_pipe_reaction, set_tank_reaction +from .s20_mixing import set_mixing, add_mixing, delete_mixing +from .s21_times import set_time +from .s23_options_util import set_option, set_option_v3 +from .s25_vertices import set_vertex, add_vertex, delete_vertex +from .s26_labels import set_label, add_label, delete_label +from .s27_backdrop import set_backdrop +from .s29_scada_device import set_scada_device, add_scada_device, delete_scada_device +from .s30_scada_device_data import set_scada_device_data, add_scada_device_data, delete_scada_device_data +from .s31_scada_element import set_scada_element, add_scada_element, delete_scada_element +from .s32_region import set_region, add_region, delete_region +from .s33_dma import set_district_metering_area, add_district_metering_area, delete_district_metering_area +from .s34_sa import set_service_area, add_service_area, delete_service_area +from .s35_vd import set_virtual_district, add_virtual_district, delete_virtual_district +from .batch_api_cs import rewrite_batch_api + + +def _execute_add_command(name: str, cs: ChangeSet) -> ChangeSet: + type = cs.operations[0]['type'] + + if type == s1_title: + return ChangeSet() + if type == s2_junction: + return add_junction(name, cs) + elif type == s3_reservoir: + return add_reservoir(name, cs) + elif type == s4_tank: + return add_tank(name, cs) + elif type == s5_pipe: + return add_pipe(name, cs) + elif type == s6_pump: + return add_pump(name, cs) + elif type == s7_valve: + return add_valve(name, cs) + elif type == s8_tag: + return ChangeSet() + elif type == s9_demand: + return ChangeSet() + elif type == s10_status: + return ChangeSet() + elif type == s11_pattern: + return add_pattern(name, cs) + elif type == s12_curve: + return add_curve(name, cs) + elif type == s13_control: + return ChangeSet() + elif type == s14_rule: + return ChangeSet() + elif type == s15_energy: + return ChangeSet() + elif type == s15_pump_energy: + return ChangeSet() + elif type == s16_emitter: + return ChangeSet() + elif type == s17_quality: + return ChangeSet() + elif type == s18_source: + return add_source(name, cs) + elif type == s19_reaction: + return ChangeSet() + elif type == s19_pipe_reaction: + return ChangeSet() + elif type == s19_tank_reaction: + return ChangeSet() + elif type == s20_mixing: + return add_mixing(name, cs) + elif type == s21_time: + return ChangeSet() + elif type == s22_report: + return ChangeSet() + elif type == s23_option: + return ChangeSet() + elif type == s23_option_v3: + return ChangeSet() + elif type == s24_coordinate: + return ChangeSet() + elif type == s25_vertex: + return add_vertex(name, cs) + elif type == s26_label: + return add_label(name, cs) + elif type == s27_backdrop: + return ChangeSet() + elif type == s28_end: + return ChangeSet() + elif type == s29_scada_device: + return add_scada_device(name, cs) + elif type == s30_scada_device_data: + return add_scada_device_data(name, cs) + elif type == s31_scada_element: + return add_scada_element(name, cs) + elif type == s32_region: + return add_region(name, cs) + elif type == s33_dma: + return add_district_metering_area(name, cs) + elif type == s34_sa: + return add_service_area(name, cs) + elif type == s35_vd: + return add_virtual_district(name, cs) + + return ChangeSet() + + +def _execute_update_command(name: str, cs: ChangeSet) -> ChangeSet: + type = cs.operations[0]['type'] + + if type == 'extension_data': + return set_extension_data(name, cs) + if type == s1_title: + return set_title(name, cs) + if type == s2_junction: + return set_junction(name, cs) + elif type == s3_reservoir: + return set_reservoir(name, cs) + elif type == s4_tank: + return set_tank(name, cs) + elif type == s5_pipe: + return set_pipe(name, cs) + elif type == s6_pump: + return set_pump(name, cs) + elif type == s7_valve: + return set_valve(name, cs) + elif type == s8_tag: + return set_tag(name, cs) + elif type == s9_demand: + return set_demand(name, cs) + elif type == s10_status: + return set_status(name, cs) + elif type == s11_pattern: + return set_pattern(name, cs) + elif type == s12_curve: + return set_curve(name, cs) + elif type == s13_control: + return set_control(name, cs) + elif type == s14_rule: + return set_rule(name, cs) + elif type == s15_energy: + return set_energy(name, cs) + elif type == s15_pump_energy: + return set_pump_energy(name, cs) + elif type == s16_emitter: + return set_emitter(name, cs) + elif type == s17_quality: + return set_quality(name, cs) + elif type == s18_source: + return set_source(name, cs) + elif type == s19_reaction: + return set_reaction(name, cs) + elif type == s19_pipe_reaction: + return set_pipe_reaction(name, cs) + elif type == s19_tank_reaction: + return set_tank_reaction(name, cs) + elif type == s20_mixing: + return set_mixing(name, cs) + elif type == s21_time: + return set_time(name, cs) + elif type == s22_report: # no api now + return ChangeSet() + elif type == s23_option: + return set_option(name, cs) + elif type == s23_option_v3: + return set_option_v3(name, cs) + elif type == s24_coordinate: # do not support update here + return ChangeSet() + elif type == s25_vertex: + return set_vertex(name, cs) + elif type == s26_label: + return set_label(name, cs) + elif type == s27_backdrop: + return set_backdrop(name, cs) + elif type == s28_end: # end + return ChangeSet() + elif type == s29_scada_device: + return set_scada_device(name, cs) + elif type == s30_scada_device_data: + return set_scada_device_data(name, cs) + elif type == s31_scada_element: + return set_scada_element(name, cs) + elif type == s32_region: + return set_region(name, cs) + elif type == s33_dma: + return set_district_metering_area(name, cs) + elif type == s34_sa: + return set_service_area(name, cs) + elif type == s35_vd: + return set_virtual_district(name, cs) + + return ChangeSet() + + +def _execute_delete_command(name: str, cs: ChangeSet) -> ChangeSet: + type = cs.operations[0]['type'] + + if type == s1_title: + return ChangeSet() + if type == s2_junction: + return delete_junction(name, cs) + elif type == s3_reservoir: + return delete_reservoir(name, cs) + elif type == s4_tank: + return delete_tank(name, cs) + elif type == s5_pipe: + return delete_pipe(name, cs) + elif type == s6_pump: + return delete_pump(name, cs) + elif type == s7_valve: + return delete_valve(name, cs) + elif type == s8_tag: + return ChangeSet() + elif type == s9_demand: + return ChangeSet() + elif type == s10_status: + return ChangeSet() + elif type == s11_pattern: + return delete_pattern(name, cs) + elif type == s12_curve: + return delete_curve(name, cs) + elif type == s13_control: + return ChangeSet() + elif type == s14_rule: + return ChangeSet() + elif type == s15_energy: + return ChangeSet() + elif type == s15_pump_energy: + return ChangeSet() + elif type == s16_emitter: + return ChangeSet() + elif type == s17_quality: + return ChangeSet() + elif type == s18_source: + return delete_source(name, cs) + elif type == s19_reaction: + return ChangeSet() + elif type == s19_pipe_reaction: + return ChangeSet() + elif type == s19_tank_reaction: + return ChangeSet() + elif type == s20_mixing: + return delete_mixing(name, cs) + elif type == s21_time: + return ChangeSet() + elif type == s22_report: + return ChangeSet() + elif type == s23_option: + return ChangeSet() + elif type == s23_option_v3: + return ChangeSet() + elif type == s24_coordinate: + return ChangeSet() + elif type == s25_vertex: + return delete_vertex(name, cs) + elif type == s26_label: + return delete_label(name, cs) + elif type == s27_backdrop: + return ChangeSet() + elif type == s28_end: + return ChangeSet() + elif type == s29_scada_device: + return delete_scada_device(name, cs) + elif type == s30_scada_device_data: + return delete_scada_device_data(name, cs) + elif type == s31_scada_element: + return delete_scada_element(name, cs) + elif type == s32_region: + return delete_region(name, cs) + elif type == s33_dma: + return delete_district_metering_area(name, cs) + elif type == s34_sa: + return delete_service_area(name, cs) + elif type == s35_vd: + return delete_virtual_district(name, cs) + + return ChangeSet() + + +def execute_batch_commands(name: str, cs: ChangeSet) -> ChangeSet: + new_cs = ChangeSet() + for op in cs.operations: + new_cs.merge(rewrite_batch_api(name, ChangeSet(op))) + + result = ChangeSet() + + todo = {} + + try: + for op in new_cs.operations: + todo = op + operation = op['operation'] + if operation == API_ADD: + result.merge(_execute_add_command(name, ChangeSet(op))) + elif operation == API_UPDATE: + result.merge(_execute_update_command(name, ChangeSet(op))) + elif operation == API_DELETE: + result.merge(_execute_delete_command(name, ChangeSet(op))) + except: + print(f'ERROR: Fail to execute {todo}') + + return result + + +def execute_batch_command(name: str, cs: ChangeSet) -> ChangeSet: + write(name, 'delete from batch_operation where id > 0') + write(name, "update operation_table set option = 'batch_operation' where option = 'operation'") + + new_cs = ChangeSet() + for op in cs.operations: + new_cs.merge(rewrite_batch_api(name, ChangeSet(op))) + + result = ChangeSet() + + todo = {} + + try: + for op in new_cs.operations: + todo = op + operation = op['operation'] + if operation == API_ADD: + result.merge(_execute_add_command(name, ChangeSet(op))) + elif operation == API_UPDATE: + result.merge(_execute_update_command(name, ChangeSet(op))) + elif operation == API_DELETE: + result.merge(_execute_delete_command(name, ChangeSet(op))) + except: + print(f'ERROR: Fail to execute {todo}') + + count = read(name, 'select count(*) as count from batch_operation')['count'] + if count == 1: + write(name, 'delete from batch_operation where id > 0') + write(name, "update operation_table set option = 'operation' where option = 'batch_operation'") + return ChangeSet() + + redo_list: list[str] = [] + redo_cs_list: list[dict[str, Any]] = [] + redo_rows = read_all(name, 'select redo, redo_cs from batch_operation where id > 0 order by id asc') + for row in redo_rows: + redo_list.append(row['redo']) + redo_cs_list += eval(row['redo_cs']) + + undo_list: list[str] = [] + undo_cs_list: list[dict[str, Any]] = [] + undo_rows = read_all(name, 'select undo, undo_cs from batch_operation where id > 0 order by id desc') + for row in undo_rows: + undo_list.append(row['undo']) + undo_cs_list += eval(row['undo_cs']) + + redo = '\n'.join(redo_list).replace("'", "''") + redo_cs = str(redo_cs_list).replace("'", "''") + undo = '\n'.join(undo_list).replace("'", "''") + undo_cs = str(undo_cs_list).replace("'", "''") + + parent = get_current_operation(name) + write(name, f"insert into operation (id, redo, undo, parent, redo_cs, undo_cs) values (default, '{redo}', '{undo}', {parent}, '{redo_cs}', '{undo_cs}')") + current = read(name, 'select max(id) as id from operation')['id'] + write(name, f"update current_operation set id = {current}") + + write(name, 'delete from batch_operation where id > 0') + write(name, "update operation_table set option = 'operation' where option = 'batch_operation'") + + return result diff --git a/app/native/wndb/clean_api.py b/app/native/wndb/clean_api.py new file mode 100644 index 0000000..ba3d7f8 --- /dev/null +++ b/app/native/wndb/clean_api.py @@ -0,0 +1,45 @@ +from .database import ChangeSet, read_all +from .batch_exe import execute_batch_command + +# TODO: merge to batch_api + +def clean_scada_device_cs(name: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, 'select id from scada_device acs') + for row in rows: + cs.delete({ 'type': 'scada_device', 'id': row['id'] }) + + return cs + + +def clean_scada_device_data_cs(name: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, 'select distinct device_id from scada_device_data acs') + for row in rows: + cs.update({ 'type': 'scada_device_data', 'device_id': row['device_id'], 'data': [] }) + + return cs + + +def clean_scada_element_cs(name: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, 'select id from scada_element acs') + for row in rows: + cs.delete({ 'type': 'scada_element', 'id': row['id'] }) + + return cs + + +def clean_scada_device(name: str) -> ChangeSet: + return execute_batch_command(name, clean_scada_device_cs(name)) + + +def clean_scada_device_data(name: str) -> ChangeSet: + return execute_batch_command(name, clean_scada_device_data_cs(name)) + + +def clean_scada_element(name: str) -> ChangeSet: + return execute_batch_command(name, clean_scada_element_cs(name)) diff --git a/app/native/wndb/connection.py b/app/native/wndb/connection.py new file mode 100644 index 0000000..b42b481 --- /dev/null +++ b/app/native/wndb/connection.py @@ -0,0 +1,3 @@ +import psycopg as pg + +g_conn_dict : dict[str, pg.Connection] = {} \ No newline at end of file diff --git a/app/native/wndb/database.py b/app/native/wndb/database.py new file mode 100644 index 0000000..c043d03 --- /dev/null +++ b/app/native/wndb/database.py @@ -0,0 +1,349 @@ +from typing import Any +from psycopg.rows import dict_row, Row +from .connection import g_conn_dict as conn + +API_ADD = 'add' +API_UPDATE = 'update' +API_DELETE = 'delete' + +g_add_prefix = { 'operation': API_ADD } +g_update_prefix = { 'operation': API_UPDATE } +g_delete_prefix = { 'operation': API_DELETE } + + +class ChangeSet: + def __init__(self, ps: dict[str, Any] | None = None): + self.operations : list[dict[str, Any]] = [] + if ps != None: + self.append(ps) + + @staticmethod + def from_list(ps: list[dict[str, Any]]): + cs = ChangeSet() + for _cs in ps: + cs.append(_cs) + return cs + + def add(self, ps: dict[str, Any]): + self.operations.append(g_add_prefix | ps) + return self + + def update(self, ps: dict[str, Any]): + self.operations.append(g_update_prefix | ps) + return self + + def delete(self, ps: dict[str, Any]): + self.operations.append(g_delete_prefix | ps) + return self + + def append(self, ps: dict[str, Any]): + self.operations.append(ps) + return self + + def merge(self, cs): + if len(cs.operations) > 0: + self.operations += cs.operations + return self + + def dump(self): + for op in self.operations: + print(op) + + def compress(self): + return self + + +class DbChangeSet: + def __init__(self, redo_sql: str, undo_sql: str, redo_cs: list[dict[str, Any]], undo_cs: list[dict[str, Any]]) -> None: + self.redo_sql = redo_sql + self.undo_sql = undo_sql + self.redo_cs = redo_cs + self.undo_cs = undo_cs + + @staticmethod + def from_list(css): + redo_sql_s : list[str] = [] + undo_sql_s : list[str] = [] + redo_cs_s : list[dict[str, Any]] = [] + undo_cs_s : list[dict[str, Any]] = [] + + for r in css: + redo_sql_s.append(r.redo_sql) + undo_sql_s.append(r.undo_sql) + redo_cs_s += r.redo_cs + r.undo_cs.reverse() # reverse again... + undo_cs_s += r.undo_cs + + redo_sql = '\n'.join(redo_sql_s) + undo_sql_s.reverse() + undo_sql = '\n'.join(undo_sql_s) + undo_cs_s.reverse() + + return DbChangeSet(redo_sql, undo_sql, redo_cs_s, undo_cs_s) + + +def read(name: str, sql: str) -> Row: + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(sql) + row = cur.fetchone() + if row == None: + raise Exception(sql) + return row + + +def read_all(name: str, sql: str) -> list[Row]: + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(sql) + return cur.fetchall() + + +def try_read(name: str, sql: str) -> Row | None: + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(sql) + return cur.fetchone() + + +def write(name: str, sql: str) -> None: + with conn[name].cursor() as cur: + cur.execute(sql) + + +def get_current_operation(name: str) -> int: + return int(read(name, 'select id from current_operation')['id']) + + +def execute_command(name: str, command: DbChangeSet, undo_redo: bool = True) -> ChangeSet: + write(name, command.redo_sql) + + if undo_redo: + op_table = read(name, "select * from operation_table")['option'] + parent = get_current_operation(name) + redo_sql = command.redo_sql.replace("'", "''") + undo_sql = command.undo_sql.replace("'", "''") + redo_cs_str = str(command.redo_cs).replace("'", "''") + undo_cs_str = str(command.undo_cs).replace("'", "''") + write(name, f"insert into {op_table} (id, redo, undo, parent, redo_cs, undo_cs) values (default, '{redo_sql}', '{undo_sql}', {parent}, '{redo_cs_str}', '{undo_cs_str}')") + + if op_table == 'operation': + current = read(name, 'select max(id) as id from operation')['id'] + write(name, f"update current_operation set id = {current}") + + return ChangeSet.from_list(command.redo_cs) + + +def execute_undo(name: str, discard: bool = False) -> ChangeSet: + row = read(name, f'select * from operation where id = {get_current_operation(name)}') + + write(name, row['undo']) + + # update foreign key + write(name, f"update current_operation set id = {row['parent']} where id = {row['id']}") + + if discard: + # update foreign key + write(name, f"update operation set redo_child = null where id = {row['parent']}") + # on delete cascade => child & snapshot + write(name, f"delete from operation where id = {row['id']}") + else: + write(name, f"update operation set redo_child = {row['id']} where id = {row['parent']}") + + e = eval(row['undo_cs']) + return ChangeSet.from_list(e) + + +def execute_redo(name: str) -> ChangeSet: + row = read(name, f'select * from operation where id = {get_current_operation(name)}') + if row['redo_child'] == None: + return ChangeSet() + + row = read(name, f"select * from operation where id = {row['redo_child']}") + write(name, row['redo']) + + write(name, f"update current_operation set id = {row['id']} where id = {row['parent']}") + + e = eval(row['redo_cs']) + return ChangeSet.from_list(e) + + +def list_snapshot(name: str) -> list[tuple[int, str]]: + rows = read_all(name, f'select * from snapshot_operation order by id') + result = [] + for row in rows: + result.append((int(row['id']), str(row['tag']))) + return result + + +def have_snapshot(name: str, tag: str) -> bool: + return try_read(name, f"select id from snapshot_operation where tag = '{tag}'") != None + + +def have_snapshot_for_operation(name: str, operation: int) -> bool: + return try_read(name, f"select id from snapshot_operation where id = {operation}") != None + + +def have_snapshot_for_current_operation(name: str) -> bool: + return have_snapshot_for_operation(name, get_current_operation(name)) + + +def take_snapshot_for_operation(name: str, operation: int, tag: str) -> None: + if tag == None or tag == '': + return None + write(name, f"insert into snapshot_operation (id, tag) values ({operation}, '{tag}')") + + +def take_snapshot_for_current_operation(name: str, tag: str) -> None: + take_snapshot_for_operation(name, get_current_operation(name), tag) + + +# deprecated ! use take_snapshot_for_current_operation instead +def take_snapshot(name: str, tag: str) -> None: + take_snapshot_for_current_operation(name, tag) + + +def update_snapshot(name: str, operation: int, tag: str) -> None: + if tag == None or tag == '': + return None + if have_snapshot_for_operation(name, operation): + write(name, f"update snapshot_operation set tag = '{tag}' where id = {operation}") + else: + take_snapshot_for_operation(name, operation, tag) + + +def update_snapshot_for_current_operation(name: str, tag: str) -> None: + return update_snapshot(name, get_current_operation(name), tag) + + +def delete_snapshot(name: str, tag: str) -> None: + write(name, f"delete from snapshot_operation where tag = '{tag}'") + + +def delete_snapshot_by_operation(name: str, operation: int) -> None: + write(name, f"delete from snapshot_operation where id = {operation}") + + +def get_operation_by_snapshot(name: str, tag: str) -> int | None: + row = try_read(name, f"select id from snapshot_operation where tag = '{tag}'") + return int(row['id']) if row != None else None + + +def get_snapshot_by_operation(name: str, operation: int) -> str | None: + row = try_read(name, f"select tag from snapshot_operation where id = {operation}") + return str(row['tag']) if row != None else None + + +def _get_parents(name: str, id: int) -> list[int]: + ids = [id] + while ids[-1] != 0: + row = read(name, f'select parent from operation where id = {ids[-1]}') + ids.append(int(row['parent'])) + return ids + + +def pick_operation(name: str, operation: int, discard: bool) -> ChangeSet: + target = operation + curr = get_current_operation(name) + + curr_parents = _get_parents(name, curr) + target_parents = _get_parents(name, target) + + change = ChangeSet() + + if target in curr_parents: + for _ in range(curr_parents.index(target)): + change.merge(execute_undo(name, discard)) + + elif curr in target_parents: + target_parents.reverse() + curr_index = target_parents.index(curr) + for i in range(curr_index, len(target_parents) - 1): + write(name, f"update operation set redo_child = '{target_parents[i + 1]}' where id = '{target_parents[i]}'") + change.merge(execute_redo(name)) + + else: + ancestor_index = -1 + while curr_parents[ancestor_index] == target_parents[ancestor_index]: + ancestor_index -= 1 + ancestor = curr_parents[ancestor_index + 1] + + for _ in range(curr_parents.index(ancestor)): + change.merge(execute_undo(name, discard)) + + target_parents.reverse() + curr_index = target_parents.index(ancestor) + for i in range(curr_index, len(target_parents) - 1): + write(name, f"update operation set redo_child = '{target_parents[i + 1]}' where id = '{target_parents[i]}'") + change.merge(execute_redo(name)) + + return change.compress() + + +def pick_snapshot(name: str, tag: str, discard: bool) -> ChangeSet: + if not have_snapshot(name, tag): + return ChangeSet() + + target = int(read(name, f"select id from snapshot_operation where tag = '{tag}'")['id']) + return pick_operation(name, target, discard) + + +def _get_change_set(name: str, operation: int, undo: bool) -> ChangeSet: + row = read(name, f'select * from operation where id = {operation}') + field= 'undo_cs' if undo else 'redo_cs' + return ChangeSet.from_list(eval(row[field])) + + +def sync_with_server(name: str, operation: int) -> ChangeSet: + fr = operation + to = get_current_operation(name) + + fr_parents = _get_parents(name, fr) + to_parents = _get_parents(name, to) + + change = ChangeSet() + + if fr in to_parents: + index = to_parents.index(fr) - 1 + while index >= 0: + change.merge(_get_change_set(name, to_parents[index], False)) #redo + index -= 1 + + elif to in fr_parents: + index = 0 + while index <= fr_parents.index(to) - 1: + change.merge(_get_change_set(name, fr_parents[index], True)) + index += 1 + + else: + ancestor_index = -1 + while fr_parents[ancestor_index] == to_parents[ancestor_index]: + ancestor_index -= 1 + + ancestor = fr_parents[ancestor_index + 1] + + index = 0 + while index <= fr_parents.index(ancestor) - 1: + change.merge(_get_change_set(name, fr_parents[index], True)) + index += 1 + + index = to_parents.index(ancestor) - 1 + while index >= 0: + change.merge(_get_change_set(name, to_parents[index], False)) + index -= 1 + + return change.compress() + + +def get_restore_operation(name: str) -> int: + return read(name, f'select * from restore_operation')['id'] + + +def set_restore_operation(name: str, operation: int) -> None: + write(name, f'update restore_operation set id = {operation}') + + +def set_restore_operation_to_current(name: str) -> None: + return set_restore_operation(name, get_current_operation(name)) + + +def restore(name: str, discard: bool) -> ChangeSet: + op = get_restore_operation(name) + return pick_operation(name, op, discard) diff --git a/app/native/wndb/extension_data.py b/app/native/wndb/extension_data.py new file mode 100644 index 0000000..cfce4ea --- /dev/null +++ b/app/native/wndb/extension_data.py @@ -0,0 +1,62 @@ +from .database import * + + +def get_all_extension_data_keys(name: str) -> list[str]: + result: list[str] = [] + for row in read_all(name, 'select key from extension_data'): + result.append(row['key']) + return result + + +def get_all_extension_data(name: str) -> dict[str, Any]: + result: dict[str, Any] = {} + for row in read_all(name, 'select key, value from extension_data'): + result[row['key']] = row['value'] + return result + + +def get_extension_data(name: str, key: str) -> str | None: + if key == None or key == '': + return None + row = try_read(name, f"select value from extension_data where key = '{key}'") + if row == None: + return None + return row['value'] + + +def _set_extension_data(name: str, cs: ChangeSet) -> DbChangeSet: + op = cs.operations[0] + key, new_val = op['key'], op['value'] + + f_new_val = f"'{new_val}'" if new_val != None else 'null' + + old_val = get_extension_data(name, key) + f_old_val = f"'{old_val}'" if old_val != None else 'null' + + redo_sql = f"delete from extension_data where key = '{key}';" + if new_val != None: + redo_sql += f"insert into extension_data (key, value) values ('{key}', {f_new_val});" + + undo_sql = f"delete from extension_data where key = '{key}';" + if old_val != None: + undo_sql += f"insert into extension_data (key, value) values ('{key}', {f_old_val});" + + redo_cs = g_update_prefix | { 'type': 'extension_data', 'key': key, 'value': new_val } + undo_cs = g_update_prefix | { 'type': 'extension_data', 'key': key, 'value': old_val } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_extension_data(name: str, cs: ChangeSet) -> ChangeSet: + if len(cs.operations) != 1: + return ChangeSet() + + op = cs.operations[0] + if 'key' not in op or 'value' not in op: + return ChangeSet() + + key = op['key'] + if key == None or key == '': + return ChangeSet() + + return execute_command(name, _set_extension_data(name, cs)) diff --git a/app/native/wndb/inp_in.py b/app/native/wndb/inp_in.py new file mode 100644 index 0000000..183202e --- /dev/null +++ b/app/native/wndb/inp_in.py @@ -0,0 +1,459 @@ +import datetime +import os +from .project import * +from .database import ChangeSet, write +from .sections import * +from .s0_base import get_region_type +from .s1_title import inp_in_title +from .s2_junctions import inp_in_junction +from .s3_reservoirs import inp_in_reservoir +from .s4_tanks import inp_in_tank +from .s5_pipes import inp_in_pipe +from .s6_pumps import inp_in_pump +from .s7_valves import inp_in_valve +from .s8_tags import inp_in_tag +from .s9_demands import inp_in_demand +from .s10_status import inp_in_status +from .s11_patterns import pattern_v3_types, inp_in_pattern +from .s12_curves import curve_types, inp_in_curve +from .s13_controls import inp_in_control +from .s14_rules import inp_in_rule +from .s15_energy import inp_in_energy +from .s16_emitters import inp_in_emitter +from .s17_quality import inp_in_quality +from .s18_sources import inp_in_source +from .s19_reactions import inp_in_reaction +from .s20_mixing import inp_in_mixing +from .s21_times import inp_in_time +from .s22_report import inp_in_report +from .s23_options import inp_in_option +from .s23_options_v3 import inp_in_option_v3 +from .s24_coordinates import inp_in_coord +from .s25_vertices import inp_in_vertex +from .s26_labels import inp_in_label +from .s27_backdrop import inp_in_backdrop +from .s32_region import inp_in_region, inp_in_bound, inp_in_regionnodes +from .s32_region_util import from_postgis_polygon, to_postgis_polygon + +# DingZQ, 2024-12-28, export inp +from .inp_out import export_inp + +_S = "S" +_L = "L" + + +def _inp_in_option(section: list[str], version: str = "3") -> str: + return inp_in_option_v3(section) if version == "3" else inp_in_option(section) + + +_handler = { + TITLE: (_S, inp_in_title), + JUNCTIONS: (_L, inp_in_junction), # line, demand_outside + RESERVOIRS: (_L, inp_in_reservoir), + TANKS: (_L, inp_in_tank), + PIPES: (_L, inp_in_pipe), + PUMPS: (_L, inp_in_pump), + VALVES: (_L, inp_in_valve), + TAGS: (_L, inp_in_tag), + DEMANDS: (_L, inp_in_demand), + STATUS: (_L, inp_in_status), + PATTERNS: (_L, inp_in_pattern), # line, fixed + CURVES: (_L, inp_in_curve), + CONTROLS: (_L, inp_in_control), + RULES: (_L, inp_in_rule), + ENERGY: (_L, inp_in_energy), + EMITTERS: (_L, inp_in_emitter), + QUALITY: (_L, inp_in_quality), + SOURCES: (_L, inp_in_source), + REACTIONS: (_L, inp_in_reaction), + MIXING: (_L, inp_in_mixing), + TIMES: (_S, inp_in_time), + REPORT: (_S, inp_in_report), + OPTIONS: (_S, _inp_in_option), # line, version + COORDINATES: (_L, inp_in_coord), + VERTICES: (_L, inp_in_vertex), + REGION: (_L, inp_in_region), + BOUND: (_L, inp_in_bound), + REGION_NODES: (_L, inp_in_regionnodes), + LABELS: (_L, inp_in_label), + BACKDROP: (_S, inp_in_backdrop), + # END : 'END', +} + +_level_1 = [ + TITLE, + PATTERNS, + CURVES, + CONTROLS, + RULES, + TIMES, + REPORT, + OPTIONS, + BACKDROP, +] + +_level_2 = [ + JUNCTIONS, + RESERVOIRS, + TANKS, +] + +_level_3 = [ + PIPES, + PUMPS, + VALVES, + DEMANDS, + EMITTERS, + QUALITY, + SOURCES, + MIXING, + COORDINATES, + LABELS, +] + +_level_4 = [ + TAGS, + STATUS, + ENERGY, + REACTIONS, + VERTICES, + REGION, + BOUND, + REGION_NODES, +] + +map_regiontype = { + # map the region types from desktop to server + "DISTRIBUTION": "WDA", + "DMA": "DMA", + "PMA": "PMA", + "VD": "VD", + "SA": "SA", +} + + +class SQLBatch: + def __init__(self, project: str, count: int = 100) -> None: + self.batch: list[str] = [] + self.project = project + self.count = count + + def add(self, sql: str) -> None: + self.batch.append(sql) + if len(self.batch) == self.count: + self.flush() + + def flush(self) -> None: + write(self.project, "".join(self.batch)) + self.batch.clear() + + +def _print_time(desc: str) -> datetime.datetime: + now = datetime.datetime.now() + time = now.strftime("%Y-%m-%d %H:%M:%S") + print(f"{time}: {desc}") + return now + + +def _get_file_offset(inp: str) -> tuple[dict[str, list[int]], bool]: + offset: dict[str, list[int]] = {} + + current = "" + demand_outside = False + + with open(inp) as f: + while True: + line = f.readline() + if not line: + break + + line = line.strip() + if line.startswith("["): + for s in section_name: + if line.startswith(f"[{s}"): + if s not in offset: + offset[s] = [] + offset[s].append(f.tell()) + current = s + break + elif line != "" and line.startswith(";") == False: + if current == DEMANDS: + demand_outside = True + + return (offset, demand_outside) + + +def parse_file(project: str, inp: str, version: str = "3") -> None: + start = _print_time(f'Start reading file "{inp}"...') + + _print_time("First scan...") + offset, demand_outside = _get_file_offset(inp) + + levels = _level_1 + _level_2 + _level_3 + _level_4 + + # parse the whole section rather than line + sections: dict[str, list[str]] = {} + for [s, t] in _handler.items(): + if t[0] == _S: + sections[s] = [] + + variable_patterns = [] + current_pattern = None + current_curve = None + curve_type_desc_line = None + current_region = None + current_bound = [] + current_bound.clear() + region_list = {} + current_region_nodes = [] + current_region_nodes.clear() + + sql_batch = SQLBatch(project) + _print_time("Second scan...") + with open(inp) as f: + for s in levels: + if s not in offset: + continue + + if s == DEMANDS and demand_outside == False: + continue + + _print_time(f"[{s}]") + + is_s = _handler[s][0] == _S + handler = _handler[s][1] + + for ptr in offset[s]: + f.seek(ptr) + + while True: + line = f.readline() + if not line: + break + + line = line.strip() + if line.startswith("["): + break + elif line == "": + continue + + if is_s: + sections[s].append(line) + else: + if line.startswith(";"): + if version != "3": # v2 + line = line.removeprefix(";") + if s == PATTERNS: # ;desc + pass + elif s == CURVES: # ;type: desc + curve_type_desc_line = line + continue + + if s == PATTERNS: + tokens = line.split() + + if tokens[1].upper() in pattern_v3_types: # v3 + sql_batch.add( + f"insert into _pattern (id) values ('{tokens[0]}');" + ) + current_pattern = tokens[0] + if tokens[1].upper() == "VARIABLE": + variable_patterns.append(tokens[0]) + continue + + if current_pattern != tokens[0]: + sql_batch.add( + f"insert into _pattern (id) values ('{tokens[0]}');" + ) + current_pattern = tokens[0] + + elif s == CURVES: + tokens = line.split() + + if tokens[1].upper() in curve_types: # v3 + sql_batch.add( + f"insert into _curve (id, type) values ('{tokens[0]}', '{tokens[1].upper()}');" + ) + current_curve = tokens[0] + continue + + if current_curve != tokens[0]: + type = curve_types[0] + if curve_type_desc_line != None: + type = curve_type_desc_line.split(":")[0].strip() + sql_batch.add( + f"insert into _curve (id, type) values ('{tokens[0]}', '{type}');" + ) + current_curve = tokens[0] + curve_type_desc_line = None + elif s == REGION: + tokens = line.split() + region_list[tokens[0]] = tokens[1] + elif s == BOUND: + tokens = line.split() + if tokens[0] != current_region and len(current_bound) > 0: + # insert the previous region after get all the vertex of the attatched geometry + current_bound.append(current_bound[0]) + current_geometry = to_postgis_polygon(current_bound) + region_type = map_regiontype[region_list[tokens[0]]] + sql_batch.add( + f"insert into region(id, boundary,r_type) values ('{current_region}', '{current_geometry}','{region_type}');" + ) + # start the new region + current_bound.clear() + vertex_point = (float(tokens[1]), float(tokens[2])) + current_bound.append(vertex_point) + current_region = tokens[0] + elif s == REGION_NODES: + tokens = line.split() + if ( + tokens[0] != current_region + and len(current_region_nodes) > 0 + ): + # insert the previous region after get all the vertex of the attatched geometry + sql_batch.add( + get_insert_into_region_sql( + current_region, current_region_nodes + ) + ) + # start the new region + current_region_nodes.clear() + current_region_nodes.append(tokens[1]) + current_region = tokens[0] + if s == JUNCTIONS: + sql_batch.add(handler(line, demand_outside)) + elif s == PATTERNS: + sql_batch.add( + handler(line, current_pattern not in variable_patterns) + ) + elif s == BOUND or s == REGION_NODES: + continue + else: + sql_batch.add(handler(line)) + + f.seek(0) + + if is_s: + if s == OPTIONS: + sql_batch.add(handler(sections[s], version)) + else: + sql_batch.add(handler(sections[s])) + # need to insert the last region into database + if len(current_bound) > 0: + current_bound.append(current_bound[0]) + current_geometry = to_postgis_polygon(current_bound) + region_type = map_regiontype[region_list[current_region]] + sql_batch.add( + f"insert into region(id, boundary,r_type) values ('{current_region}', '{current_geometry}','{region_type}');" + ) + # reset the current region to none for the [REGION_NODES] session reading + # current_region=None + # need to insert the last region_nodes into database + if len(current_region_nodes) > 0: + sql_batch.add( + get_insert_into_region_sql(current_region, current_region_nodes) + ) + # current_region=None + sql_batch.flush() + + end = _print_time(f'End reading file "{inp}"') + print(f"Total (in second): {(end-start).seconds}(s)") + + +def get_insert_into_region_sql(region: str, nodes: list[str]) -> str: + str_sql = "" + str_nodes = str(nodes).replace("'", "''") + r_type = region[0 : region.index("_")] + if r_type == "DMA" or r_type == "SA" or r_type == "VD": + table = "" + if r_type == "DMA": + table = "region_dma" + elif r_type == "SA": + table = "region_sa" + source = region[region.index("_") + 1 :] + str_sql = f"insert into region_sa(id,time_index,source,nodes) values ('{region}', 0,'{source}','{str_nodes}');" + elif r_type == "VD": + table = "region_vd" + + return str_sql + + +def read_inp(project: str, inp: str, version: str = "3") -> bool: + if version != "3" and version != "2": + version = "2" + + if is_project_open(project): + close_project(project) + + if have_project(project): + delete_project(project) + + create_project(project) + open_project(project) + + parse_file(project, inp, version) + + """try: + parse_file(project, inp, version) + except: + close_project(project) + delete_project(project) + return False""" + + close_project(project) + return True + + +# DingZQ, 2024-12-28, convert v3 to v2 +def convert_inp_v3_to_v2(inp: str) -> ChangeSet: + project = "v3Tov2" + + if is_project_open(project): + close_project(project) + + if have_project(project): + delete_project(project) + + create_project(project) + open_project(project) + + filename = f"inp/{project}_temp.inp" + if os.path.exists(filename): + os.remove(filename) + + with open(filename, "w") as f: + f.write(inp) + + parse_file(project, filename, "3") + + """try: + parse_file(project, inp, version) + except: + close_project(project) + delete_project(project) + return False""" + + return export_inp(project, "2") + + +def import_inp(project: str, cs: ChangeSet, version: str = "3") -> bool: + if version != "3" and version != "2": + version = "2" + + if "inp" not in cs.operations[0]: + return False + + filename = f"inp/{project}_temp.inp" + if os.path.exists(filename): + os.remove(filename) + + _print_time(f'Start writing temp file "{filename}"...') + with open(filename, "w", encoding="GBK") as f: + f.write(str(cs.operations[0]["inp"])) + _print_time(f'End writing temp file "{filename}"...') + + result = read_inp(project, filename, version) + + # os.remove(filename) + + return result diff --git a/app/native/wndb/inp_out.py b/app/native/wndb/inp_out.py new file mode 100644 index 0000000..aa7de7e --- /dev/null +++ b/app/native/wndb/inp_out.py @@ -0,0 +1,287 @@ +import os +from .project import * +from .database import ChangeSet +from .sections import * +from .s1_title import inp_out_title +from .s2_junctions import inp_out_junction +from .s3_reservoirs import inp_out_reservoir +from .s4_tanks import inp_out_tank +from .s5_pipes import inp_out_pipe +from .s6_pumps import inp_out_pump +from .s7_valves import inp_out_valve +from .s8_tags import inp_out_tag +from .s9_demands import inp_out_demand +from .s10_status import inp_out_status +from .s11_patterns import inp_out_pattern, inp_out_pattern_v3 +from .s12_curves import inp_out_curve, inp_out_curve_v3 +from .s13_controls import inp_out_control +from .s14_rules import inp_out_rule +from .s15_energy import inp_out_energy +from .s16_emitters import inp_out_emitter +from .s17_quality import inp_out_quality +from .s18_sources import inp_out_source +from .s19_reactions import inp_out_reaction +from .s20_mixing import inp_out_mixing +from .s21_times import inp_out_time +from .s22_report import inp_out_report +from .s23_options import inp_out_option +from .s23_options_v3 import inp_out_option_v3 +from .s24_coordinates import inp_out_coord +from .s25_vertices import inp_out_vertex +from .s26_labels import inp_out_label +from .s27_backdrop import inp_out_backdrop +#from .s28_end import * + + +def dump_inp(project: str, inp: str, version: str = '3'): + if version != '3' and version != '2': + version = '2' + + if not have_project(project): + return + + project_open = is_project_open(project) + + if not project_open: + open_project(project) + + dir = os.getcwd() + path = os.path.join(dir, inp) + + if os.path.exists(path): + os.remove(path) + + file = open(path, mode='w',encoding="UTF-8") + + # REGION, BOUND, REGION_NODES 在 epanet v2 中没有,是我们自己定制的 + # v2 需要去掉我们自己定制的 section + sections = section_names_for_epanetv2 + if version == '3': + sections = section_name + + for name in sections: + if name == TITLE: + file.write(f'[{name}]\n') + else: + file.write(f'\n[{name}]\n') + + if name == TITLE: + file.write('\n'.join(inp_out_title(project))) + + elif name == JUNCTIONS: # + coords + file.write('\n'.join(inp_out_junction(project))) + + elif name == RESERVOIRS: # + coords + file.write('\n'.join(inp_out_reservoir(project))) + + elif name == TANKS: # + coords + file.write('\n'.join(inp_out_tank(project))) + + elif name == PIPES: + file.write('\n'.join(inp_out_pipe(project))) + + elif name == PUMPS: + file.write('\n'.join(inp_out_pump(project))) + + elif name == VALVES: + file.write('\n'.join(inp_out_valve(project))) + + elif name == TAGS: + file.write('\n'.join(inp_out_tag(project))) + + elif name == DEMANDS: + file.write('\n'.join(inp_out_demand(project))) + + elif name == STATUS: + file.write('\n'.join(inp_out_status(project))) + + elif name == PATTERNS: + if version == '3': + file.write('\n'.join(inp_out_pattern_v3(project))) + else: + file.write('\n'.join(inp_out_pattern(project))) + + elif name == CURVES: + if version == '3': + file.write('\n'.join(inp_out_curve_v3(project))) + else: + file.write('\n'.join(inp_out_curve(project))) + + elif name == CONTROLS: + file.write('\n'.join(inp_out_control(project))) + + elif name == RULES: + file.write('\n'.join(inp_out_rule(project))) + + elif name == ENERGY: + file.write('\n'.join(inp_out_energy(project))) + + elif name == EMITTERS: + file.write('\n'.join(inp_out_emitter(project))) + + elif name == QUALITY: + file.write('\n'.join(inp_out_quality(project))) + + elif name == SOURCES: + file.write('\n'.join(inp_out_source(project))) + + elif name == REACTIONS: + file.write('\n'.join(inp_out_reaction(project))) + + elif name == MIXING: + file.write('\n'.join(inp_out_mixing(project))) + + elif name == TIMES: + file.write('\n'.join(inp_out_time(project))) + + elif name == REPORT: + file.write('\n'.join(inp_out_report(project))) + + elif name == OPTIONS: + if version == '3': + file.write('\n'.join(inp_out_option_v3(project))) + else: + file.write('\n'.join(inp_out_option(project))) + + elif name == COORDINATES: + file.write('\n'.join(inp_out_coord(project))) + + elif name == VERTICES: + file.write('\n'.join(inp_out_vertex(project))) + + elif name == LABELS: + file.write('\n'.join(inp_out_label(project))) + + elif name == BACKDROP: + file.write('\n'.join(inp_out_backdrop(project))) + + elif name == END: + pass # :) + + file.write('\n') + + file.close() + + if not project_open: + close_project(project) + + +def export_inp(project: str, version: str = '3') -> ChangeSet: + if version != '3' and version != '2': + version = '2' + + if not have_project(project): + return ChangeSet() + + project_open = is_project_open(project) + + if not project_open: + open_project(project) + + inp = '' + + for name in section_name: + if name == TITLE: + inp += f'[{name}]\n' + else: + inp += f'\n[{name}]\n' + + if name == TITLE: + inp += '\n'.join(inp_out_title(project)) + + elif name == JUNCTIONS: # + coords + inp += '\n'.join(inp_out_junction(project)) + + elif name == RESERVOIRS: # + coords + inp += '\n'.join(inp_out_reservoir(project)) + + elif name == TANKS: # + coords + inp += '\n'.join(inp_out_tank(project)) + + elif name == PIPES: + inp += '\n'.join(inp_out_pipe(project)) + + elif name == PUMPS: + inp += '\n'.join(inp_out_pump(project)) + + elif name == VALVES: + inp += '\n'.join(inp_out_valve(project)) + + elif name == TAGS: + inp += '\n'.join(inp_out_tag(project)) + + elif name == DEMANDS: + inp += '\n'.join(inp_out_demand(project)) + + elif name == STATUS: + inp += '\n'.join(inp_out_status(project)) + + elif name == PATTERNS: + if version == '3': + inp += '\n'.join(inp_out_pattern_v3(project)) + else: + inp += '\n'.join(inp_out_pattern(project)) + + elif name == CURVES: + if version == '3': + inp += '\n'.join(inp_out_curve_v3(project)) + else: + inp += '\n'.join(inp_out_curve(project)) + + elif name == CONTROLS: + inp += '\n'.join(inp_out_control(project)) + + elif name == RULES: + inp += '\n'.join(inp_out_rule(project)) + + elif name == ENERGY: + inp += '\n'.join(inp_out_energy(project)) + + elif name == EMITTERS: + inp += '\n'.join(inp_out_emitter(project)) + + elif name == QUALITY: + inp += '\n'.join(inp_out_quality(project)) + + elif name == SOURCES: + inp += '\n'.join(inp_out_source(project)) + + elif name == REACTIONS: + inp += '\n'.join(inp_out_reaction(project)) + + elif name == MIXING: + inp += '\n'.join(inp_out_mixing(project)) + + elif name == TIMES: + inp += '\n'.join(inp_out_time(project)) + + elif name == REPORT: + inp += '\n'.join(inp_out_report(project)) + + elif name == OPTIONS: + if version == '3': + inp += '\n'.join(inp_out_option_v3(project)) + else: + inp += '\n'.join(inp_out_option(project)) + + elif name == COORDINATES: + inp += '\n'.join(inp_out_coord(project)) + + elif name == VERTICES: + inp += '\n'.join(inp_out_vertex(project)) + + elif name == LABELS: + inp += '\n'.join(inp_out_label(project)) + + elif name == BACKDROP: + inp += '\n'.join(inp_out_backdrop(project)) + + elif name == END: + pass # :) + + inp += '\n' + + if not project_open: + close_project(project) + + return ChangeSet({'operation': 'export', 'inp': inp}) diff --git a/app/native/wndb/project.py b/app/native/wndb/project.py new file mode 100644 index 0000000..25b9328 --- /dev/null +++ b/app/native/wndb/project.py @@ -0,0 +1,192 @@ +import os +import psycopg as pg +from psycopg import sql +from psycopg.rows import dict_row +from .connection import g_conn_dict as conn +from app.core.config import get_pgconn_string, get_pg_config, get_pg_password + +# no undo/redo + +_server_databases = ["template0", "template1", "postgres", "project"] + + +def list_project() -> list[str]: + ps = [] + with pg.connect(conninfo=get_pgconn_string(), autocommit=True) as conn: + with conn.cursor(row_factory=dict_row) as cur: + for p in cur.execute( + f"select datname from pg_database where datname <> 'postgres' and datname <> 'template0' and datname <> 'template1' and datname <> 'project'" + ): + ps.append(p["datname"]) + return ps + + +def have_project(name: str) -> bool: + with pg.connect( + conninfo=get_pgconn_string(db_name="postgres"), autocommit=True + ) as conn: + with conn.cursor() as cur: + cur.execute("select 1 from pg_database where datname = %s", (name,)) + return cur.fetchone() is not None + + +def copy_project(source: str, new: str) -> None: + if source in conn: + conn[source].close() + del conn[source] + + with pg.connect( + conninfo=get_pgconn_string(db_name="postgres"), autocommit=True + ) as admin_conn: + with admin_conn.cursor() as cur: + cur.execute( + "update pg_database set datallowconn = false where datname = %s", + (source,), + ) + try: + cur.execute( + "select pg_terminate_backend(pid) from pg_stat_activity where datname = %s and pid <> pg_backend_pid()", + (source,), + ) + cur.execute( + sql.SQL("create database {} with template = {}").format( + sql.Identifier(new), sql.Identifier(source) + ) + ) + finally: + cur.execute( + "update pg_database set datallowconn = true where datname = %s", + (source,), + ) + + +# 2025-02-07, WMH +# copyproject会把pg中operation这个表的全部内容也加进去,我们实际项目运行一周后operation这个表会变得特别大,导致CopyProject花费的时间很长,CopyProjectEx把operation的在复制时没有一块复制过去,节省时间 +class CopyProjectEx: + @staticmethod + def create_database(connection, new_db): + with connection.cursor() as cursor: + cursor.execute(f'create database "{new_db}"') + connection.commit() + + @staticmethod + def execute_pg_dump(source_db, exclude_table_list): + + os.environ["PGPASSWORD"] = get_pg_password() # 设置密码环境变量 + pg_config = get_pg_config() + host = pg_config["host"] + port = pg_config["port"] + user = pg_config["user"] + dump_command_structure = f"pg_dump -h {host} -p {port} -U {user} -F c -s -f source_db_structure.dump {source_db}" + os.system(dump_command_structure) + + if exclude_table_list is not None: + exclude_table = " ".join(["-T {}".format(i) for i in exclude_table_list]) + dump_command_db = f"pg_dump -h {host} -p {port} -U {user} -F c -a {exclude_table} -f source_db.dump {source_db}" + else: + dump_command_db = f"pg_dump -h {host} -p {port} -U {user} -F c -a -f source_db.dump {source_db}" + os.system(dump_command_db) + + @staticmethod + def execute_pg_restore(new_db): + os.environ["PGPASSWORD"] = get_pg_password() # 设置密码环境变量 + pg_config = get_pg_config() + host = pg_config["host"] + port = pg_config["port"] + user = pg_config["user"] + restore_command_structure = f"pg_restore -h {host} -p {port} -U {user} -d {new_db} source_db_structure.dump" + os.system(restore_command_structure) + + restore_command_db = ( + f"pg_restore -h {host} -p {port} -U {user} -d {new_db} source_db.dump" + ) + os.system(restore_command_db) + + @staticmethod + def init_operation_table(connection, excluded_table): + with connection.cursor() as cursor: + if "operation" in excluded_table: + insert_query = "insert into operation (id, redo, undo, redo_cs, undo_cs) values (0, '', '', '', '')" + cursor.execute(insert_query) + + if "current_operation" in excluded_table: + insert_query = "insert into current_operation (id) values (0)" + cursor.execute(insert_query) + + if "restore_operation" in excluded_table: + insert_query = "insert into restore_operation (id) values (0)" + cursor.execute(insert_query) + + if "batch_operation" in excluded_table: + insert_query = "insert into batch_operation (id, redo, undo, redo_cs, undo_cs) values (0, '', '', '', '')" + cursor.execute(insert_query) + + if "operation_table" in excluded_table: + insert_query = ( + "insert into operation_table (option) values ('operation')" + ) + cursor.execute(insert_query) + connection.commit() + + def __call__(self, source: str, new_db: str, excluded_tables: [str] = None) -> None: + source_connection = pg.connect(conninfo=get_pgconn_string(), autocommit=True) + + self.create_database(source_connection, new_db) + + self.execute_pg_dump(source, excluded_tables) + self.execute_pg_restore(new_db) + source_connection.close() + + new_db_connection = pg.connect( + conninfo=get_pgconn_string(db_name=new_db), autocommit=True + ) + self.init_operation_table(new_db_connection, excluded_tables) + new_db_connection.close() + + +def create_project(name: str) -> None: + return copy_project("project", name) + + +def delete_project(name: str) -> None: + with pg.connect(conninfo=get_pgconn_string(), autocommit=True) as conn: + with conn.cursor() as cur: + cur.execute( + f"select pg_terminate_backend(pid) from pg_stat_activity where datname = '{name}'" + ) + cur.execute(f'drop database "{name}"') + + +def clean_project(excluded: list[str] = []) -> None: + projects = list_project() + with pg.connect(conninfo=get_pgconn_string(), autocommit=True) as conn: + with conn.cursor(row_factory=dict_row) as cur: + row = cur.execute(f"select current_database()").fetchone() + if row != None: + current_db = row["current_database"] + if current_db in projects: + projects.remove(current_db) + for project in projects: + if project in _server_databases or project in excluded: + continue + cur.execute( + f"select pg_terminate_backend(pid) from pg_stat_activity where datname = '{project}'" + ) + cur.execute(f'drop database "{project}"') + + +def open_project(name: str) -> None: + if name not in conn: + conn[name] = pg.connect( + conninfo=get_pgconn_string(db_name=name), autocommit=True + ) + + +def is_project_open(name: str) -> bool: + return name in conn + + +def close_project(name: str) -> None: + if name in conn: + conn[name].close() + del conn[name] diff --git a/app/native/wndb/s0_base.py b/app/native/wndb/s0_base.py new file mode 100644 index 0000000..65882ab --- /dev/null +++ b/app/native/wndb/s0_base.py @@ -0,0 +1,262 @@ +from psycopg.rows import dict_row, Row +from .connection import g_conn_dict as conn +from .database import read +from typing import Any + +_NODE = '_node' +_LINK = '_link' +_CURVE = '_curve' +_PATTERN = '_pattern' +_REGION = '_region' + +JUNCTION = 'junction' +RESERVOIR = 'reservoir' +TANK = 'tank' +PIPE = 'pipe' +PUMP = 'pump' +VALVE = 'valve' + +PATTERN = 'pattern' +CURVE = 'curve' + +REGION = 'region' + +# DingZQ, 2025-02-05 +''' + C++ 代码里已经定义了这些 enum 值 +{ + kNothing = -1, + + //Node + kReservoir = 0, + kTank, + kJunction, + + //Link + kPipe, + kPump, + kValve, +''' +ELEMENT_TYPES : dict[str, int] = { + RESERVOIR : 0, + TANK : 1, + JUNCTION : 2, + PIPE : 3, + PUMP : 4, + VALVE : 5, +} + +def _get_from(name: str, id: str, base_type: str) -> Row | None: + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select * from {base_type} where id = '{id}'") + return cur.fetchone() + + +def is_node(name: str, id: str) -> bool: + return _get_from(name, id, _NODE) != None + + +def is_junction(name: str, id: str) -> bool: + row = _get_from(name, id, _NODE) + return row != None and row['type'] == JUNCTION + + +def is_reservoir(name: str, id: str) -> bool: + row = _get_from(name, id, _NODE) + return row != None and row['type'] == RESERVOIR + + +def is_tank(name: str, id: str) -> bool: + row = _get_from(name, id, _NODE) + return row != None and row['type'] == TANK + + +def is_link(name: str, id: str) -> bool: + return _get_from(name, id, _LINK) != None + + +def is_pipe(name: str, id: str) -> bool: + row = _get_from(name, id, _LINK) + return row != None and row['type'] == PIPE + + +def is_pump(name: str, id: str) -> bool: + row = _get_from(name, id, _LINK) + return row != None and row['type'] == PUMP + + +def is_valve(name: str, id: str) -> bool: + row = _get_from(name, id, _LINK) + return row != None and row['type'] == VALVE + +# DingZQ, 2025-02-05 +def get_node_type(name: str, node_id: str) -> str: + row = _get_from(name, node_id, _NODE) + return row['type'] + + +def get_link_type(name: str, link_id: str) -> str: + row = _get_from(name, link_id, _LINK) + return row['type'] + +def get_element_type(name: str, element_id: str) -> str: + if is_node(name, element_id): + return get_node_type(name, element_id) + elif is_link(name, element_id): + return get_link_type(name, element_id) + else: + return None + +def get_element_type_value(name: str, element_id: str) -> int: + return ELEMENT_TYPES[get_element_type(name, element_id)] + +def is_curve(name: str, id: str) -> bool: + + return _get_from(name, id, _CURVE) != None + + +def is_pattern(name: str, id: str) -> bool: + return _get_from(name, id, _PATTERN) != None + + +def is_region(name: str, id: str) -> bool: + return _get_from(name, id, _REGION) != None + + +def _get_all(name: str, base_type: str) -> list[str]: + ids : list[str] = [] + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select id from {base_type} order by id") + for record in cur: + ids.append(record['id']) + return ids + + +def get_nodes(name: str) -> list[str]: + return _get_all(name, _NODE) + +# DingZQ +def _get_nodes_by_type(name: str, type: str) -> list[str]: + ids : list[str] = [] + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select id from {_NODE} where type = '{type}' order by id") + for record in cur: + ids.append(record['id']) + return ids + +# DingZQ +def get_nodes_id_and_type(name: str) -> dict[str, str]: + nodes_id_and_type: dict[str, str] = {} + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select id, type from {_NODE} order by id") + for record in cur: + nodes_id_and_type[record['id']] = record['type'] + return nodes_id_and_type + +# DingZQ 2024-12-31 +def get_major_nodes(name: str, diameter: int) -> list[str]: + major_nodes_set = set() + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select node1, node2 from pipes where diameter > {diameter}") + for record in cur: + major_nodes_set.add(record['node1']) + major_nodes_set.add(record['node2']) + + return list(major_nodes_set) + +# DingZQs +def get_junctions(name: str) -> list[str]: + return _get_nodes_by_type(name, JUNCTION) + +# DingZQ +def get_reservoirs(name: str) -> list[str]: + return _get_nodes_by_type(name, RESERVOIR) + +# DingZQ +def get_tanks(name: str) -> list[str]: + return _get_nodes_by_type(name, TANK) + +# DingZQ +def get_links(name: str) -> list[str]: + return _get_all(name, _LINK) + +# DingZQ +def _get_links_by_type(name: str, type: str) -> list[str]: + ids : list[str] = [] + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select id from {_LINK} where type = '{type}' order by id") + for record in cur: + ids.append(record['id']) + return ids + +# DingZQ +def get_links_id_and_type(name: str) -> dict[str, str]: + links_id_and_type: dict[str, str] = {} + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select id, type from {_LINK} order by id") + for record in cur: + links_id_and_type[record['id']] = record['type'] + return links_id_and_type + +# DingZQ 2024-12-31 +# 获取直径大于800的管道 +def get_major_pipes(name: str, diameter: int) -> list[str]: + major_pipe_ids: list[str] = [] + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select id from pipes where diameter > {diameter} order by id") + for record in cur: + major_pipe_ids.append(record['id']) + return major_pipe_ids + +# DingZQ +def get_pipes(name: str) -> list[str]: + return _get_links_by_type(name, PIPE) + +# DingZQ +def get_pumps(name: str) -> list[str]: + return _get_links_by_type(name, PUMP) + +# DingZQ +def get_valves(name: str) -> list[str]: + return _get_links_by_type(name, VALVE) + + +def get_curves(name: str) -> list[str]: + return _get_all(name, _CURVE) + + +def get_patterns(name: str) -> list[str]: + return _get_all(name, _PATTERN) + +def get_regions(name: str) -> list[str]: + return _get_all(name, _REGION) + +def get_node_links(name: str, id: str) -> list[str]: + with conn[name].cursor(row_factory=dict_row) as cur: + links: list[str] = [] + for p in cur.execute(f"select id from pipes where node1 = '{id}' or node2 = '{id}'").fetchall(): + links.append(p['id']) + for p in cur.execute(f"select id from pumps where node1 = '{id}' or node2 = '{id}'").fetchall(): + links.append(p['id']) + for p in cur.execute(f"select id from valves where node1 = '{id}' or node2 = '{id}'").fetchall(): + links.append(p['id']) + return links + + +def get_link_nodes(name: str, id: str) -> list[str]: + row = {} + if is_pipe(name, id): + row = read(name, f"select node1, node2 from pipes where id = '{id}'") + elif is_pump(name, id): + row = read(name, f"select node1, node2 from pumps where id = '{id}'") + elif is_valve(name, id): + row = read(name, f"select node1, node2 from valves where id = '{id}'") + return [str(row['node1']), str(row['node2'])] + +def get_region_type(name: str, id: str)->str: + if(is_region(name,id)): + type = read(name, f"select type from _region where id = '{id}'") + return type + + + diff --git a/app/native/wndb/s10_status.py b/app/native/wndb/s10_status.py new file mode 100644 index 0000000..33b2a7d --- /dev/null +++ b/app/native/wndb/s10_status.py @@ -0,0 +1,110 @@ +from .database import * + + +LINK_STATUS_OPEN = 'OPEN' +LINK_STATUS_CLOSED = 'CLOSED' +LINK_STATUS_ACTIVE = 'ACTIVE' + + +def get_status_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'link' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'status' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'setting' : {'type': 'float' , 'optional': True , 'readonly': False} } + + +def get_status(name: str, link: str) -> dict[str, Any]: + s = try_read(name, f"select * from status where link = '{link}'") + if s == None: + return { 'link': link, 'status': None, 'setting': None } + d = {} + d['link'] = str(s['link']) + d['status'] = str(s['status']) if s['status'] != None else None + d['setting'] = float(s['setting']) if s['setting'] != None else None + return d + + +class Status(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'status' + self.link = str(input['link']) + self.status = str(input['status']) if 'status' in input and input['status'] != None else None + self.setting = float(input['setting']) if 'setting' in input and input['setting'] != None else None + + self.f_type = f"'{self.type}'" + self.f_link = f"'{self.link}'" + self.f_status = f"'{self.status}'" if self.status != None else 'null' + self.f_setting = self.setting if self.setting != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'link': self.link, 'status': self.status, 'setting': self.setting } + + +def _set_status(name: str, cs: ChangeSet) -> DbChangeSet: + old = Status(get_status(name, cs.operations[0]['link'])) + raw_new = get_status(name, cs.operations[0]['link']) + + new_dict = cs.operations[0] + schema = get_status_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Status(raw_new) + + redo_sql = f"delete from status where link = {new.f_link};" + if new.status != None or new.setting != None: + redo_sql += f"\ninsert into status (link, status, setting) values ({new.f_link}, {new.f_status}, {new.f_setting});" + + undo_sql = f"delete from status where link = {old.f_link};" + if old.status != None or old.setting != None: + undo_sql += f"\ninsert into status (link, status, setting) values ({old.f_link}, {old.f_status}, {old.f_setting});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_status(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_status(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# link value +#-------------------------------------------------------------- + + +def inp_in_status(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + link = str(tokens[0]) + value = tokens[1].upper() + if value == LINK_STATUS_OPEN or value == LINK_STATUS_CLOSED or value == LINK_STATUS_ACTIVE: + return str(f"insert into status (link, status, setting) values ('{link}', '{value}', null);") + else: + return str(f"insert into status (link, status, setting) values ('{link}', null, {float(value)});") + + +def inp_out_status(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from status') + for obj in objs: + link = obj['link'] + status = obj['status'] if obj['status'] != None else '' + setting = obj['setting'] if obj['setting'] != None else '' + if status != '': + lines.append(f'{link} {status}') + if setting != '': + lines.append(f'{link} {setting}') + return lines + + +def delete_status_by_link(name: str, link: str) -> ChangeSet: + row = try_read(name, f"select * from status where link = '{link}'") + if row == None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type': 'status', 'link': link, 'status': None, 'setting': None}) diff --git a/app/native/wndb/s11_patterns.py b/app/native/wndb/s11_patterns.py new file mode 100644 index 0000000..382d554 --- /dev/null +++ b/app/native/wndb/s11_patterns.py @@ -0,0 +1,163 @@ +from .database import * + +PATTERN_V3_TYPE_FIXED = 'FIXED' +PATTERN_V3_TYPE_VARIABLE = 'VARIABLE' + +pattern_v3_types = [PATTERN_V3_TYPE_FIXED, PATTERN_V3_TYPE_VARIABLE] + +def get_pattern_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'factors' : {'type': 'float_list' , 'optional': False , 'readonly': False } } + + +def get_pattern(name: str, id: str) -> dict[str, Any]: + p_one = try_read(name, f"select * from _pattern where id = '{id}'") + if p_one == None: + return {} + pas = read_all(name, f"select * from patterns where id = '{id}' order by _order") + ps = [] + for r in pas: + ps.append(float(r['factor'])) + return { 'id': id, 'factors': ps } + + +def _set_pattern(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + old = get_pattern(name, id) + + new = { 'id': id } + if 'factors' in cs.operations[0]: + new['factors'] = cs.operations[0]['factors'] + else: + new['factors'] = old['factors'] + + # TODO: transaction ? + redo_sql = f"delete from patterns where id = {f_id};" + for f_factor in new['factors']: + redo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" + + undo_sql = f"delete from patterns where id = {f_id};" + for f_factor in old['factors']: + undo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" + + redo_cs = g_update_prefix | { 'type': 'pattern' } | new + undo_cs = g_update_prefix | { 'type': 'pattern' } | old + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_pattern(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pattern(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_pattern(name, cs)) + + +def _add_pattern(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + new = { 'id': id, 'factors': cs.operations[0]['factors'] } + + # TODO: transaction ? + redo_sql = f"insert into _pattern (id) values ({f_id});" + for f_factor in new['factors']: + redo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" + + undo_sql = f"delete from patterns where id = {f_id};" + undo_sql += f"\ndelete from _pattern where id = {f_id};" + + redo_cs = g_add_prefix | { 'type': 'pattern' } | new + undo_cs = g_delete_prefix | { 'type': 'pattern' } | { 'id': id } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_pattern(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pattern(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_pattern(name, cs)) + + +def _delete_pattern(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + old = get_pattern(name, id) + + redo_sql = f"delete from patterns where id = {f_id};" + redo_sql += f"\ndelete from _pattern where id = {f_id};" + + # TODO: transaction ? + undo_sql = f"insert into _pattern (id) values ({f_id});" + for f_factor in old['factors']: + undo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});" + + redo_cs = g_delete_prefix | { 'type': 'pattern' } | { 'id': id } + undo_cs = g_add_prefix | { 'type': 'pattern' } | old + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_pattern(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pattern(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_pattern(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][IN][OUT] +# ;desc +# id mult1 mult2 ..... +#-------------------------------------------------------------- +#-------------------------------------------------------------- +# [EPA3][IN][OUT] +# id FIXED (interval) +# id factor1 factor2 ... +# id VARIABLE +# id time1 factor1 time2 factor2 ... +#-------------------------------------------------------------- + + +def inp_in_pattern(line: str, fixed: bool = True) -> str: + tokens = line.split() + sql = '' + if fixed: + for token in tokens[1:]: + sql += f"insert into patterns (id, factor) values ('{tokens[0]}', {float(token)});" + else: + for token in tokens[1::2]: + sql += f"insert into patterns (id, factor) values ('{tokens[0]}', {float(token)});" + return sql + + +def inp_out_pattern(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from patterns order by _order") + for obj in objs: + id = obj['id'] + factor = obj['factor'] + lines.append(f'{id} {factor}') + return lines + + +def inp_out_pattern_v3(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from patterns order by _order") + ids = [] + for obj in objs: + id = obj['id'] + if id not in ids: + # for EPA3, ignore time of variable pattern... + lines.append(f'{id} FIXED') + ids.append(id) + factor = obj['factor'] + lines.append(f'{id} {factor}') + return lines diff --git a/app/native/wndb/s12_curves.py b/app/native/wndb/s12_curves.py new file mode 100644 index 0000000..eb37982 --- /dev/null +++ b/app/native/wndb/s12_curves.py @@ -0,0 +1,186 @@ +from .database import * + +CURVE_TYPE_PUMP = 'PUMP' +CURVE_TYPE_EFFICIENCY = 'EFFICIENCY' +CURVE_TYPE_VOLUME = 'VOLUME' +CURVE_TYPE_HEADLOSS = 'HEADLOSS' + +curve_types = [CURVE_TYPE_PUMP, CURVE_TYPE_EFFICIENCY, CURVE_TYPE_VOLUME, CURVE_TYPE_HEADLOSS] + +def get_curve_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'c_type' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'coords' : {'type': 'list' , 'optional': False , 'readonly': False, + 'element': { 'x' : {'type': 'float' , 'optional': False , 'readonly': False }, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False } }}} + + +def get_curve(name: str, id: str) -> dict[str, Any]: + c_one = try_read(name, f"select * from _curve where id = '{id}'") + if c_one == None: + return {} + cus = read_all(name, f"select * from curves where id = '{id}' order by _order") + cs = [] + for r in cus: + cs.append({ 'x': float(r['x']), 'y': float(r['y']) }) + d = {} + d['id'] = id + d['c_type'] = c_one['type'] + d['coords'] = cs + return d + + +def _set_curve(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + old = get_curve(name, id) + old_f_type = f"'{old['c_type']}'" + + new = { 'id': id } + if 'coords' in cs.operations[0]: + new['coords'] = cs.operations[0]['coords'] + else: + new['coords'] = old['coords'] + if 'c_type' in cs.operations[0]: + new['c_type'] = cs.operations[0]['c_type'] + else: + new['c_type'] = old['c_type'] + new_f_type = f"'{new['c_type']}'" + + # TODO: transaction ? + redo_sql = f"delete from curves where id = {f_id};" + redo_sql += f"\nupdate _curve set type = {new_f_type} where id = {f_id};" + for xy in new['coords']: + f_x, f_y = xy['x'], xy['y'] + redo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" + + undo_sql = f"delete from curves where id = {f_id};" + undo_sql += f"\nupdate _curve set type = {old_f_type} where id = {f_id};" + for xy in old['coords']: + f_x, f_y = xy['x'], xy['y'] + undo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" + + redo_cs = g_update_prefix | { 'type': 'curve' } | new + undo_cs = g_update_prefix | { 'type': 'curve' } | old + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_curve(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_curve(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_curve(name, cs)) + + +def _add_curve(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + new = { 'id': id, 'c_type': cs.operations[0]['c_type'], 'coords': [] } + new_f_type = f"'{new['c_type']}'" + + # TODO: transaction ? + redo_sql = f"insert into _curve (id, type) values ({f_id}, {new_f_type});" + for xy in cs.operations[0]['coords']: + x, y = float(xy['x']), float(xy['y']) + f_x, f_y = x, y + redo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" + new['coords'].append({ 'x': x, 'y': y }) + + undo_sql = f"delete from curves where id = {f_id};" + undo_sql += f"\ndelete from _curve where id = {f_id};" + + redo_cs = g_add_prefix | { 'type': 'curve' } | new + undo_cs = g_delete_prefix | { 'type': 'curve' } | { 'id' : id } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_curve(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_curve(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_curve(name, cs)) + + +def _delete_curve(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + f_id = f"'{id}'" + + old = get_curve(name, id) + old_f_type = f"'{old['c_type']}'" + + redo_sql = f"delete from curves where id = {f_id};" + redo_sql += f"\ndelete from _curve where id = {f_id};" + + # TODO: transaction ? + undo_sql = f"insert into _curve (id, type) values ({f_id}, {old_f_type});" + for xy in old['coords']: + f_x, f_y = xy['x'], xy['y'] + undo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});" + + redo_cs = g_delete_prefix | { 'type': 'curve' } | { 'id' : id } + undo_cs = g_add_prefix | { 'type': 'curve' } | old + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_curve(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_curve(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_curve(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][IN][OUT] +# ;type: desc +# id x y +#-------------------------------------------------------------- +#-------------------------------------------------------------- +# [EPA3][IN][OUT] +# id type +# id x y +#-------------------------------------------------------------- + + +def inp_in_curve(line: str) -> str: + tokens = line.split() + return str(f"insert into curves (id, x, y) values ('{tokens[0]}', {float(tokens[1])}, {float(tokens[2])});") + + +def inp_out_curve(name: str) -> list[str]: + lines = [] + types = read_all(name, f"select * from _curve") + for type in types: + id = type['id'] + # ;type: desc + lines.append(f";{type['type']}:") + objs = read_all(name, f"select * from curves where id = '{id}' order by _order") + for obj in objs: + id = obj['id'] + x = obj['x'] + y = obj['y'] + lines.append(f'{id} {x} {y}') + return lines + + +def inp_out_curve_v3(name: str) -> list[str]: + lines = [] + types = read_all(name, f"select * from _curve") + for type in types: + id = type['id'] + # id type + lines.append(f"{id} {type['type']}") + objs = read_all(name, f"select * from curves where id = '{id}' order by _order") + for obj in objs: + id = obj['id'] + x = obj['x'] + y = obj['y'] + lines.append(f'{id} {x} {y}') + return lines diff --git a/app/native/wndb/s13_controls.py b/app/native/wndb/s13_controls.py new file mode 100644 index 0000000..7b43f2b --- /dev/null +++ b/app/native/wndb/s13_controls.py @@ -0,0 +1,52 @@ +from .database import * + + +def get_control_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'controls' : {'type': 'str_list' , 'optional': False , 'readonly': False} } + + +def get_control(name: str) -> dict[str, Any]: + cs = read_all(name, f"select * from controls") + ds = [] + for c in cs: + ds.append(c['line']) + return { 'controls': ds } + + +def _set_control(name: str, cs: ChangeSet) -> DbChangeSet: + old = get_control(name) + + redo_sql = 'delete from controls;' + for line in cs.operations[0]['controls']: + redo_sql += f"\ninsert into controls (line) values ('{line}');" + + undo_sql = 'delete from controls;' + for line in old['controls']: + undo_sql += f"\ninsert into controls (line) values ('{line}');" + + redo_cs = g_update_prefix | { 'type': 'control', 'controls': cs.operations[0]['controls'] } + undo_cs = g_update_prefix | { 'type': 'control', 'controls': old['controls'] } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_control(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_control(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3] +# LINK linkID setting IF NODE nodeID {BELOW/ABOVE} level +# LINK linkID setting AT TIME value (units) +# LINK linkID setting AT CLOCKTIME value (units) +# (0) (1) (2) (3) (4) (5) (6) (7) +# todo... +#-------------------------------------------------------------- + + +def inp_in_control(line: str) -> str: + return str(f"insert into controls (line) values ('{line}');") + + +def inp_out_control(name: str) -> list[str]: + return get_control(name)['controls'] diff --git a/app/native/wndb/s14_rules.py b/app/native/wndb/s14_rules.py new file mode 100644 index 0000000..b210f71 --- /dev/null +++ b/app/native/wndb/s14_rules.py @@ -0,0 +1,48 @@ +from .database import * + + +def get_rule_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'rules' : {'type': 'str_list' , 'optional': False , 'readonly': False} } + + +def get_rule(name: str) -> dict[str, Any]: + cs = read_all(name, f"select * from rules") + ds = [] + for c in cs: + ds.append(c['line']) + return { 'rules': ds } + + +def _set_rule(name: str, cs: ChangeSet) -> DbChangeSet: + old = get_rule(name) + + redo_sql = 'delete from rules;' + for line in cs.operations[0]['rules']: + redo_sql += f"\ninsert into rules (line) values ('{line}');" + + undo_sql = 'delete from rules;' + for line in old['rules']: + undo_sql += f"\ninsert into rules (line) values ('{line}');" + + redo_cs = g_update_prefix | { 'type': 'rule', 'rules': cs.operations[0]['rules'] } + undo_cs = g_update_prefix | { 'type': 'rule', 'rules': old['rules'] } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_rule(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_rule(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3] +# TODO... +#-------------------------------------------------------------- + + +def inp_in_rule(line: str) -> str: + return str(f"insert into rules (line) values ('{line}');") + + +def inp_out_rule(name: str) -> list[str]: + return get_rule(name)['rules'] \ No newline at end of file diff --git a/app/native/wndb/s15_energy.py b/app/native/wndb/s15_energy.py new file mode 100644 index 0000000..3abb998 --- /dev/null +++ b/app/native/wndb/s15_energy.py @@ -0,0 +1,240 @@ +from .database import * + + +element_schema = {'type': 'str' , 'optional': True , 'readonly': False} + + +def get_energy_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'GLOBAL PRICE' : element_schema, + 'GLOBAL PATTERN' : element_schema, + 'GLOBAL EFFIC' : element_schema, + 'DEMAND CHARGE' : element_schema } + + +def get_energy(name: str) -> dict[str, Any]: + ts = read_all(name, f"select * from energy") + d = {} + for e in ts: + d[e['key']] = str(e['value']) + return d + + +def _set_energy(name: str, cs: ChangeSet) -> DbChangeSet: + raw_old = get_energy(name) + + old = {} + new = {} + + new_dict = cs.operations[0] + schema = get_energy_schema(name) + for key in schema.keys(): + if key in new_dict: + old[key] = str(raw_old[key]) + new[key] = str(new_dict[key]) + + redo_cs = g_update_prefix | { 'type' : 'energy' } + + redo_sql = '' + for key, value in new.items(): + if redo_sql != '': + redo_sql += '\n' + redo_sql += f"update energy set value = '{value}' where key = '{key}';" + redo_cs |= { key: value } + + undo_cs = g_update_prefix | { 'type' : 'energy' } + + undo_sql = '' + for key, value in old.items(): + if undo_sql != '': + undo_sql += '\n' + undo_sql += f"update energy set value = '{value}' where key = '{key}';" + undo_cs |= { key: value } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_energy(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_energy(name, cs)) + + +def get_pump_energy_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'pump' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'price' : {'type': 'float' , 'optional': True , 'readonly': False}, + 'pattern' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'effic' : {'type': 'str' , 'optional': True , 'readonly': False} } + + +def get_pump_energy(name: str, pump: str) -> dict[str, Any]: + d = {} + d['pump'] = pump + pe = try_read(name, f"select * from energy_pump_price where pump = '{pump}'") + d['price'] = float(pe['price']) if pe != None else None + pe = try_read(name, f"select * from energy_pump_pattern where pump = '{pump}'") + d['pattern'] = str(pe['pattern']) if pe != None else None + pe = try_read(name, f"select * from energy_pump_effic where pump = '{pump}'") + d['effic'] = str(pe['effic']) if pe != None else None + return d + + +class PumpEnergy(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'pump_energy' + self.pump = str(input['pump']) + self.price = float(input['price']) if 'price' in input and input['price'] != None else None + self.pattern = str(input['pattern']) if 'pattern' in input and input['pattern'] != None else None + self.effic = str(input['effic']) if 'effic' in input and input['effic'] != None else None + + self.f_type = f"'{self.type}'" + self.f_pump = f"'{self.pump}'" + self.f_price = self.price if self.price != None else 'null' + self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null' + self.f_effic = f"'{self.effic}'" if self.effic != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'pump': self.pump, 'price': self.price, 'pattern': self.pattern, 'effic': self.effic } + + +def _set_pump_energy(name: str, cs: ChangeSet) -> DbChangeSet: + old = PumpEnergy(get_pump_energy(name, cs.operations[0]['pump'])) + raw_new = get_pump_energy(name, cs.operations[0]['pump']) + + new_dict = cs.operations[0] + schema = get_pump_energy_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = PumpEnergy(raw_new) + + redo_sql = f"delete from energy_pump_price where pump = {new.f_pump};\ndelete from energy_pump_pattern where pump = {new.f_pump};\ndelete from energy_pump_effic where pump = {new.f_pump};" + if new.price != None: + redo_sql += f"\ninsert into energy_pump_price (pump, price) values ({new.f_pump}, {new.f_price});" + if new.pattern != None: + redo_sql += f"\ninsert into energy_pump_pattern (pump, pattern) values ({new.f_pump}, {new.f_pattern});" + if new.effic != None: + redo_sql += f"\ninsert into energy_pump_effic (pump, effic) values ({new.f_pump}, {new.f_effic});" + + undo_sql = f"delete from energy_pump_price where pump = {old.f_pump};\ndelete from energy_pump_pattern where pump = {old.f_pump};\ndelete from energy_pump_effic where pump = {old.f_pump};" + if old.price != None: + undo_sql += f"\ninsert into energy_pump_price (pump, price) values ({old.f_pump}, {old.f_price});" + if old.pattern != None: + undo_sql += f"\ninsert into energy_pump_pattern (pump, pattern) values ({old.f_pump}, {old.f_pattern});" + if old.effic != None: + undo_sql += f"\ninsert into energy_pump_effic (pump, effic) values ({old.f_pump}, {old.f_effic});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_pump_energy(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_pump_energy(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# GLOBAL {PRICE/PATTERN/EFFIC} value +# PUMP id {PRICE/PATTERN/EFFIC} value +# DEMAND CHARGE value +#-------------------------------------------------------------- + + +def inp_in_energy(line: str) -> str: + tokens = line.split() + + if tokens[0].upper() == 'PUMP': + pump = tokens[1] + key = tokens[2].lower() + value = tokens[3] + if key == 'price': + value = float(value) + else: + value = f"'{value}'" + if key == 'efficiency': + key = 'effic' + + return str(f"insert into energy_pump_{key} (pump, {key}) values ('{pump}', {value});") + + else: + line = line.upper().strip() + for key in get_energy_schema('').keys(): + if line.startswith(key): + value = line.removeprefix(key).strip() + + # exception here + if line.startswith('GLOBAL EFFICIENCY'): + value = line.removeprefix('GLOBAL EFFICIENCY').strip() + + return str(f"update energy set value = '{value}' where key = '{key}';") + + return str('') + + +def inp_out_energy(name: str) -> list[str]: + lines = [] + + objs = read_all(name, f"select * from energy") + for obj in objs: + key = obj['key'] + value = obj['value'] + if value.strip() != '': + lines.append(f'{key} {value}') + + objs = read_all(name, f"select * from energy_pump_price") + for obj in objs: + pump = obj['pump'] + value = obj['price'] + lines.append(f'PUMP {pump} PRICE {value}') + + objs = read_all(name, f"select * from energy_pump_pattern") + for obj in objs: + pump = obj['pump'] + value = obj['pattern'] + lines.append(f'PUMP {pump} PATTERN {value}') + + objs = read_all(name, f"select * from energy_pump_effic") + for obj in objs: + pump = obj['pump'] + value = obj['effic'] + lines.append(f'PUMP {pump} EFFIC {value}') + + return lines + + +def delete_pump_energy_by_pump(name: str, pump: str) -> ChangeSet: + row1 = try_read(name, f"select * from energy_pump_price where pump = '{pump}'") + row2 = try_read(name, f"select * from energy_pump_pattern where pump = '{pump}'") + row3 = try_read(name, f"select * from energy_pump_effic where pump = '{pump}'") + if row1 == None and row2 == None and row3 == None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type': 'pump_energy', 'pump' : pump, 'price': None, 'pattern': None, 'effic': None}) + + +def unset_pump_energy_by_pattern(name: str, pattern: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select * from energy_pump_pattern where pattern = '{pattern}'") + for row in rows: + pump = row['pump'] + row1 = try_read(name, f"select * from energy_pump_price where pump = '{pump}'") + price = float(row1['price']) if row1 != None else None + row2 = try_read(name, f"select * from energy_pump_effic where pump = '{pump}'") + effic = str(row2['effic']) if row2 != None else None + cs.append(g_update_prefix | {'type': 'pump_energy', 'pump' : pump, 'price': price, 'pattern': None, 'effic': effic}) + + return cs + + +def unset_pump_energy_by_curve(name: str, curve: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select * from energy_pump_effic where effic = '{curve}'") + for row in rows: + pump = row['pump'] + row1 = try_read(name, f"select * from energy_pump_price where pump = '{pump}'") + price = float(row1['price']) if row1 != None else None + row2 = try_read(name, f"select * from energy_pump_pattern where pump = '{pump}'") + pattern = str(row2['pattern']) if row2 != None else None + cs.append(g_update_prefix | {'type': 'pump_energy', 'pump' : pump, 'price': price, 'pattern': pattern, 'effic': None}) + + return cs diff --git a/app/native/wndb/s16_emitters.py b/app/native/wndb/s16_emitters.py new file mode 100644 index 0000000..8f510a9 --- /dev/null +++ b/app/native/wndb/s16_emitters.py @@ -0,0 +1,98 @@ +from .database import * + + +def get_emitter_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'junction' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'coefficient' : {'type': 'float' , 'optional': True , 'readonly': False} } + + +def get_emitter(name: str, junction: str) -> dict[str, Any]: + e = try_read(name, f"select * from emitters where junction = '{junction}'") + if e == None: + return { 'junction': junction, 'coefficient': None } + d = {} + d['junction'] = str(e['junction']) + d['coefficient'] = float(e['coefficient']) if e['coefficient'] != None else None + return d + + +class Emitter(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'emitter' + self.junction = str(input['junction']) + self.coefficient = float(input['coefficient']) if 'coefficient' in input and input['coefficient'] != None else None + + self.f_type = f"'{self.type}'" + self.f_junction = f"'{self.junction}'" + self.f_coefficient = self.coefficient if self.coefficient != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'junction': self.junction, 'coefficient': self.coefficient } + + +def _set_emitter(name: str, cs: ChangeSet) -> DbChangeSet: + old = Emitter(get_emitter(name, cs.operations[0]['junction'])) + raw_new = get_emitter(name, cs.operations[0]['junction']) + + new_dict = cs.operations[0] + schema = get_emitter_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Emitter(raw_new) + + redo_sql = f"delete from emitters where junction = {new.f_junction};" + if new.coefficient != None: + redo_sql += f"\ninsert into emitters (junction, coefficient) values ({new.f_junction}, {new.f_coefficient});" + + undo_sql = f"delete from emitters where junction = {old.f_junction};" + if old.coefficient != None: + undo_sql += f"\ninsert into emitters (junction, coefficient) values ({old.f_junction}, {old.f_coefficient});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_emitter(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_emitter(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][IN][OUT] +# node Ke +#-------------------------------------------------------------- +# [EPA3][IN][OUT] +# node Ke (exponent pattern) +#-------------------------------------------------------------- + + +def inp_in_emitter(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + junction = str(tokens[0]) + coefficient = float(tokens[1]) + + return str(f"insert into emitters (junction, coefficient) values ('{junction}', {coefficient});") + + +def inp_out_emitter(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from emitters') + for obj in objs: + junction = obj['junction'] + coefficient = obj['coefficient'] + lines.append(f'{junction} {coefficient}') + return lines + + +def delete_emitter_by_junction(name: str, junction: str) -> ChangeSet: + row = try_read(name, f"select * from emitters where junction = '{junction}'") + if row == None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type' : 'emitter', 'junction': junction, 'coefficient': None}) diff --git a/app/native/wndb/s17_quality.py b/app/native/wndb/s17_quality.py new file mode 100644 index 0000000..539b205 --- /dev/null +++ b/app/native/wndb/s17_quality.py @@ -0,0 +1,95 @@ +from .database import * + + +def get_quality_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'node' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'quality' : {'type': 'float' , 'optional': True , 'readonly': False} } + + +def get_quality(name: str, node: str) -> dict[str, Any]: + e = try_read(name, f"select * from quality where node = '{node}'") + if e == None: + return { 'node': node, 'quality': None } + d = {} + d['node'] = str(e['node']) + d['quality'] = float(e['quality']) if e['quality'] != None else None + return d + + +class Quality(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'quality' + self.node = str(input['node']) + self.quality = float(input['quality']) if 'quality' in input and input['quality'] != None else None + + self.f_type = f"'{self.type}'" + self.f_node = f"'{self.node}'" + self.f_quality = self.quality if self.quality != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'node': self.node, 'quality': self.quality } + + +def _set_quality(name: str, cs: ChangeSet) -> DbChangeSet: + old = Quality(get_quality(name, cs.operations[0]['node'])) + raw_new = get_quality(name, cs.operations[0]['node']) + + new_dict = cs.operations[0] + schema = get_quality_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Quality(raw_new) + + redo_sql = f"delete from quality where node = {new.f_node};" + if new.quality != None: + redo_sql += f"\ninsert into quality (node, quality) values ({new.f_node}, {new.f_quality});" + + undo_sql = f"delete from quality where node = {old.f_node};" + if old.quality != None: + undo_sql += f"\ninsert into quality (node, quality) values ({old.f_node}, {old.f_quality});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_quality(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_quality(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# node initqual +#-------------------------------------------------------------- + + +def inp_in_quality(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + node = str(tokens[0]) + quality = float(tokens[1]) + + return str(f"insert into quality (node, quality) values ('{node}', {quality});") + + +def inp_out_quality(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from quality') + for obj in objs: + node = obj['node'] + quality = obj['quality'] + lines.append(f'{node} {quality}') + return lines + + +def delete_quality_by_node(name: str, node: str) -> ChangeSet: + row = try_read(name, f"select * from quality where node = '{node}'") + if row == None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type' : 'quality', 'node': node, 'quality': None}) diff --git a/app/native/wndb/s18_sources.py b/app/native/wndb/s18_sources.py new file mode 100644 index 0000000..0abaeda --- /dev/null +++ b/app/native/wndb/s18_sources.py @@ -0,0 +1,153 @@ +from .database import * +from .s0_base import * + +SOURCE_TYPE_CONCEN = 'CONCEN' +SOURCE_TYPE_MASS = 'MASS' +SOURCE_TYPE_FLOWPACED = 'FLOWPACED' +SOURCE_TYPE_SETPOINT = 'SETPOINT' + +def get_source_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'node' : {'type': 'str' , 'optional': False , 'readonly': True }, + 's_type' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'strength' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'pattern' : {'type': 'str' , 'optional': True , 'readonly': False} } + + +def get_source(name: str, node: str) -> dict[str, Any]: + s = try_read(name, f"select * from sources where node = '{node}'") + if s == None: + return {} + d = {} + d['node'] = str(s['node']) + d['s_type'] = str(s['s_type']) + d['strength'] = float(s['strength']) + d['pattern'] = str(s['pattern']) if s['pattern'] != None else None + return d + + +class Source(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'source' + self.node = str(input['node']) + self.s_type = str(input['s_type']) + self.strength = float(input['strength']) + self.pattern = str(input['pattern']) if 'pattern' in input and input['pattern'] != None else None + + self.f_type = f"'{self.type}'" + self.f_node = f"'{self.node}'" + self.f_s_type = f"'{self.s_type}'" + self.f_strength = self.strength + self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'node': self.node, 's_type': self.s_type, 'strength': self.strength, 'pattern': self.pattern } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'node': self.node } + + +def _set_source(name: str, cs: ChangeSet) -> DbChangeSet: + old = Source(get_source(name, cs.operations[0]['node'])) + raw_new = get_source(name, cs.operations[0]['node']) + + new_dict = cs.operations[0] + schema = get_source_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Source(raw_new) + + redo_sql = f"update sources set s_type = {new.f_s_type}, strength = {new.f_strength}, pattern = {new.f_pattern} where node = {new.f_node};" + undo_sql = f"update sources set s_type = {old.f_s_type}, strength = {old.f_strength}, pattern = {old.f_pattern} where node = {old.f_node};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_source(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_source(name, cs)) + + +def _add_source(name: str, cs: ChangeSet) -> DbChangeSet: + new = Source(cs.operations[0]) + + redo_sql = f"insert into sources (node, s_type, strength, pattern) values ({new.f_node}, {new.f_s_type}, {new.f_strength}, {new.f_pattern});" + undo_sql = f"delete from sources where node = {new.f_node};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_source(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _add_source(name, cs)) + + +def _delete_source(name: str, cs: ChangeSet) -> DbChangeSet: + old = Source(get_source(name, cs.operations[0]['node'])) + + redo_sql = f"delete from sources where node = {old.f_node};" + undo_sql = f"insert into sources (node, s_type, strength, pattern) values ({old.f_node}, {old.f_s_type}, {old.f_strength}, {old.f_pattern});" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_source(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _delete_source(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# node sourcetype quality (pattern) +#-------------------------------------------------------------- + + +def inp_in_source(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + node = str(tokens[0]) + s_type = str(tokens[1].upper()) + strength = float(tokens[2]) + pattern = str(tokens[3]) if num_without_desc >= 4 else None + pattern = f"'{pattern}'" if pattern != None else 'null' + + return str(f"insert into sources (node, s_type, strength, pattern) values ('{node}', '{s_type}', {strength}, {pattern});") + + +def inp_out_source(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from sources') + for obj in objs: + node = obj['node'] + s_type = obj['s_type'] + strength = obj['strength'] + pattern = obj['pattern'] if obj['pattern'] != None else '' + lines.append(f'{node} {s_type} {strength} {pattern}') + return lines + + +def delete_source_by_node(name: str, node: str) -> ChangeSet: + row = try_read(name, f"select * from sources where node = '{node}'") + if row == None: + return ChangeSet() + return ChangeSet(g_delete_prefix | {'type' : 'source', 'node': node}) + + +def unset_source_by_pattern(name: str, pattern: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select node from sources where pattern = '{pattern}'") + for row in rows: + cs.append(g_update_prefix | {'type': 'source', 'node': row['node'], 'pattern': None}) + + return cs diff --git a/app/native/wndb/s19_reactions.py b/app/native/wndb/s19_reactions.py new file mode 100644 index 0000000..bf0faf5 --- /dev/null +++ b/app/native/wndb/s19_reactions.py @@ -0,0 +1,263 @@ +from .database import * + + +element_schema = {'type': 'str' , 'optional': True , 'readonly': False} + + +def get_reaction_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'ORDER BULK' : element_schema, + 'ORDER WALL' : element_schema, + 'ORDER TANK' : element_schema, + 'GLOBAL BULK' : element_schema, + 'GLOBAL WALL' : element_schema, + 'LIMITING POTENTIAL' : element_schema, + 'ROUGHNESS CORRELATION' : element_schema } + + +def get_reaction(name: str) -> dict[str, Any]: + ts = read_all(name, f"select * from reactions") + d = {} + for e in ts: + d[e['key']] = str(e['value']) + return d + + +def _set_reaction(name: str, cs: ChangeSet) -> DbChangeSet: + raw_old = get_reaction(name) + + old = {} + new = {} + + new_dict = cs.operations[0] + schema = get_reaction_schema(name) + for key in schema.keys(): + if key in new_dict: + old[key] = str(raw_old[key]) + new[key] = str(new_dict[key]) + + redo_cs = g_update_prefix | { 'type' : 'reaction' } + + redo_sql = '' + for key, value in new.items(): + if redo_sql != '': + redo_sql += '\n' + redo_sql += f"update reactions set value = '{value}' where key = '{key}';" + redo_cs |= { key: value } + + undo_cs = g_update_prefix | { 'type' : 'reaction' } + + undo_sql = '' + for key, value in old.items(): + if undo_sql != '': + undo_sql += '\n' + undo_sql += f"update reactions set value = '{value}' where key = '{key}';" + undo_cs |= { key: value } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_reaction(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_reaction(name, cs)) + + +def get_pipe_reaction_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'pipe' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'bulk' : {'type': 'float' , 'optional': True , 'readonly': False}, + 'wall' : {'type': 'float' , 'optional': True , 'readonly': False} } + + +def get_pipe_reaction(name: str, pipe: str) -> dict[str, Any]: + d = {} + d['pipe'] = pipe + pr = try_read(name, f"select * from reactions_pipe_bulk where pipe = '{pipe}'") + d['bulk'] = float(pr['value']) if pr != None else None + pr = try_read(name, f"select * from reactions_pipe_wall where pipe = '{pipe}'") + d['wall'] = float(pr['value']) if pr != None else None + return d + + +class PipeReaction(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'pipe_reaction' + self.pipe = str(input['pipe']) + self.bulk = float(input['bulk']) if 'bulk' in input and input['bulk'] != None else None + self.wall = float(input['wall']) if 'wall' in input and input['wall'] != None else None + + self.f_type = f"'{self.type}'" + self.f_pipe = f"'{self.pipe}'" + self.f_bulk = self.bulk if self.bulk != None else 'null' + self.f_wall = self.wall if self.wall != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'pipe': self.pipe, 'bulk': self.bulk, 'wall': self.wall } + + +def _set_pipe_reaction(name: str, cs: ChangeSet) -> DbChangeSet: + old = PipeReaction(get_pipe_reaction(name, cs.operations[0]['pipe'])) + raw_new = get_pipe_reaction(name, cs.operations[0]['pipe']) + + new_dict = cs.operations[0] + schema = get_pipe_reaction_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = PipeReaction(raw_new) + + redo_sql = f"delete from reactions_pipe_bulk where pipe = {new.f_pipe};\ndelete from reactions_pipe_wall where pipe = {new.f_pipe};" + if new.bulk != None: + redo_sql += f"\ninsert into reactions_pipe_bulk (pipe, value) values ({new.f_pipe}, {new.f_bulk});" + if new.wall != None: + redo_sql += f"\ninsert into reactions_pipe_wall (pipe, value) values ({new.f_pipe}, {new.f_wall});" + + undo_sql = f"delete from reactions_pipe_bulk where pipe = {old.f_pipe};\ndelete from reactions_pipe_wall where pipe = {old.f_pipe};" + if old.bulk != None: + undo_sql += f"\ninsert into reactions_pipe_bulk (pipe, value) values ({old.f_pipe}, {old.f_bulk});" + if old.wall != None: + undo_sql += f"\ninsert into reactions_pipe_wall (pipe, value) values ({old.f_pipe}, {old.f_wall});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_pipe_reaction(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_pipe_reaction(name, cs)) + + +def get_tank_reaction_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'tank' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'value' : {'type': 'float' , 'optional': True , 'readonly': False} } + + +def get_tank_reaction(name: str, tank: str) -> dict[str, Any]: + d = {} + d['tank'] = tank + pr = try_read(name, f"select * from reactions_tank where tank = '{tank}'") + d['value'] = float(pr['value']) if pr != None else None + return d + + +class TankReaction(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'tank_reaction' + self.tank = str(input['tank']) + self.value = float(input['value']) if 'value' in input and input['value'] != None else None + + self.f_type = f"'{self.type}'" + self.f_tank = f"'{self.tank}'" + self.f_value = self.value if self.value != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'tank': self.tank, 'value': self.value } + + +def _set_tank_reaction(name: str, cs: ChangeSet) -> DbChangeSet: + old = TankReaction(get_tank_reaction(name, cs.operations[0]['tank'])) + raw_new = get_tank_reaction(name, cs.operations[0]['tank']) + + new_dict = cs.operations[0] + schema = get_tank_reaction_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = TankReaction(raw_new) + + redo_sql = f"delete from reactions_tank where tank = {new.f_tank};" + if new.value != None: + redo_sql += f"\ninsert into reactions_tank (tank, value) values ({new.f_tank}, {new.f_value});" + + undo_sql = f"delete from reactions_tank where tank = {old.f_tank};" + if old.value != None: + undo_sql += f"\ninsert into reactions_tank (tank, value) values ({old.f_tank}, {old.f_value});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_tank_reaction(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_tank_reaction(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# ORDER {BULK/WALL/TANK} value +# GLOBAL BULK coeff +# GLOBAL WALL coeff +# BULK link1 (link2) coeff +# WALL link1 (link2) coeff +# TANK node1 (node2) coeff +# LIMITING POTENTIAL value +# ROUGHNESS CORRELATION value +#-------------------------------------------------------------- + + +def inp_in_reaction(line: str) -> str: + tokens = line.split() + token0 = tokens[0].upper() + if token0 == 'BULK' or token0 == 'WALL': + pipe = tokens[1] + key = token0.lower() + value = tokens[2] + return str(f"insert into reactions_pipe_{key} (pipe, value) values ('{pipe}', {value});") + + elif token0 == 'TANK': + tank = tokens[1] + value = tokens[2] + return str(f"insert into reactions_tank (tank, value) values ('{tank}', {value});") + + else: + line = line.upper().strip() + for key in get_reaction_schema('').keys(): + if line.startswith(key): + value = line.removeprefix(key).strip() + return str(f"update reactions set value = '{value}' where key = '{key}';") + + return str('') + + +def inp_out_reaction(name: str) -> list[str]: + lines = [] + + objs = read_all(name, f"select * from reactions") + for obj in objs: + key = obj['key'] + value = obj['value'] + lines.append(f'{key} {value}') + + objs = read_all(name, f"select * from reactions_pipe_bulk") + for obj in objs: + pipe = obj['pipe'] + value = obj['value'] + lines.append(f'BULK {pipe} {value}') + + objs = read_all(name, f"select * from reactions_pipe_wall") + for obj in objs: + pipe = obj['pipe'] + value = obj['value'] + lines.append(f'WALL {pipe} {value}') + + objs = read_all(name, f"select * from reactions_tank") + for obj in objs: + tank = obj['tank'] + value = obj['value'] + lines.append(f'TANK {tank} {value}') + + return lines + + +def delete_pipe_reaction_by_pipe(name: str, pipe: str) -> ChangeSet: + row1 = try_read(name, f"select * from reactions_pipe_bulk where pipe = '{pipe}'") + row2 = try_read(name, f"select * from reactions_pipe_wall where pipe = '{pipe}'") + if row1 == None and row2 == None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type': 'pipe_reaction', 'pipe': pipe, 'bulk': None, 'wall': None}) + + +def delete_tank_reaction_by_tank(name: str, tank: str) -> ChangeSet: + row = try_read(name, f"select * from reactions_tank where tank = '{tank}'") + if row == None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type': 'tank_reaction', 'tank': tank, 'value': None}) diff --git a/app/native/wndb/s1_title.py b/app/native/wndb/s1_title.py new file mode 100644 index 0000000..3ec5d6a --- /dev/null +++ b/app/native/wndb/s1_title.py @@ -0,0 +1,40 @@ +from .database import * + + +def get_title_schema(name: str) -> dict[str, dict[str, Any]]: + return {'value': {'type': 'float', 'optional': False, 'readonly': False}} + + +def get_title(name: str) -> dict[str, Any]: + title = read(name, 'select * from title') + return { 'value': title['value'] } + + +def _set_title(name: str, cs: ChangeSet) -> DbChangeSet: + new = cs.operations[0]['value'] + old = get_title(name)['value'] + + redo_sql = f"update title set value = '{new}';" + undo_sql = f"update title set value = '{old}';" + + redo_cs = g_update_prefix | { 'type': 'title', 'value': new } + undo_cs = g_update_prefix | { 'type': 'title', 'value': old } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_title(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_title(name ,cs)) + + +def inp_in_title(section: list[str]) -> str: + if section == []: + return str('') + + title = '\n'.join(section) + return str(f"update title set value = '{title}';") + + +def inp_out_title(name: str) -> list[str]: + obj = str(get_title(name)['value']) + return obj.split('\n') diff --git a/app/native/wndb/s20_mixing.py b/app/native/wndb/s20_mixing.py new file mode 100644 index 0000000..5bef359 --- /dev/null +++ b/app/native/wndb/s20_mixing.py @@ -0,0 +1,150 @@ +from .database import * +from .s0_base import * + +MIXING_MODEL_MIXED = 'MIXED' +MIXING_MODEL_2COMP = '2COMP' +MIXING_MODEL_FIFO = 'FIFO' +MIXING_MODEL_LIFO = 'LIFO' + +def get_mixing_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'tank' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'model' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'value' : {'type': 'float' , 'optional': True , 'readonly': False} } + + +def get_mixing(name: str, tank: str) -> dict[str, Any]: + m = try_read(name, f"select * from mixing where tank = '{tank}'") + if m == None: + return {} + d = {} + d['tank'] = str(m['tank']) + d['model'] = str(m['model']) + d['value'] = float(m['value']) if m['value'] != None else None + return d + + +class Mixing(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'mixing' + self.tank = str(input['tank']) + self.model = str(input['model']) + self.value = float(input['value']) if 'value' in input and input['value'] != None else None + + self.f_type = f"'{self.type}'" + self.f_tank = f"'{self.tank}'" + self.f_model = f"'{self.model}'" + self.f_value = self.value if self.value != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'tank': self.tank, 'model': self.model, 'value': self.value } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'tank': self.tank } + + +def _set_mixing(name: str, cs: ChangeSet) -> DbChangeSet: + old = Mixing(get_mixing(name, cs.operations[0]['tank'])) + raw_new = get_mixing(name, cs.operations[0]['tank']) + + new_dict = cs.operations[0] + schema = get_mixing_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Mixing(raw_new) + + redo_sql = f"update mixing set model = {new.f_model}, value = {new.f_value} where tank = {new.f_tank};" + undo_sql = f"update mixing set model = {old.f_model}, value = {old.f_value} where tank = {old.f_tank};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_mixing(name: str, cs: ChangeSet) -> ChangeSet: + if 'tank' not in cs.operations[0]: + return ChangeSet() + if get_mixing(name, cs.operations[0]['tank']) == {}: + return ChangeSet() + return execute_command(name, _set_mixing(name, cs)) + + +def _add_mixing(name: str, cs: ChangeSet) -> DbChangeSet: + new = Mixing(cs.operations[0]) + + redo_sql = f"insert into mixing (tank, model, value) values ({new.f_tank}, {new.f_model}, {new.f_value});" + undo_sql = f"delete from mixing where tank = {new.f_tank};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_mixing(name: str, cs: ChangeSet) -> ChangeSet: + if 'tank' not in cs.operations[0]: + return ChangeSet() + if get_mixing(name, cs.operations[0]['tank']) != {}: + return ChangeSet() + return execute_command(name, _add_mixing(name, cs)) + + +def _delete_mixing(name: str, cs: ChangeSet) -> DbChangeSet: + old = Mixing(get_mixing(name, cs.operations[0]['tank'])) + + redo_sql = f"delete from mixing where tank = {old.f_tank};" + undo_sql = f"insert into mixing (tank, model, value) values ({old.f_tank}, {old.f_model}, {old.f_value});" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_mixing(name: str, cs: ChangeSet) -> ChangeSet: + if 'tank' not in cs.operations[0]: + return ChangeSet() + if get_mixing(name, cs.operations[0]['tank']) == {}: + return ChangeSet() + return execute_command(name, _delete_mixing(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# TankID MixModel FractVolume +# FractVolume if type == MIX2 +#-------------------------------------------------------------- + + +def inp_in_mixing(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + tank = str(tokens[0]) + model = str(tokens[1].upper()) + value = float(tokens[3]) if num_without_desc >= 4 else None + value = value if value != None else 'null' + + return str(f"insert into mixing (tank, model, value) values ('{tank}', '{model}', {value});") + + +def inp_out_mixing(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from mixing') + for obj in objs: + tank = obj['tank'] + model = obj['model'] + value = obj['value'] if obj['value'] != None else '' + lines.append(f'{tank} {model} {value}') + return lines + + +def delete_mixing_by_tank(name: str, tank: str) -> ChangeSet: + row = try_read(name, f"select * from mixing where tank = '{tank}'") + if row == None: + return ChangeSet() + return ChangeSet(g_delete_prefix | {'type' : 'mixing', 'tank': tank}) diff --git a/app/native/wndb/s21_times.py b/app/native/wndb/s21_times.py new file mode 100644 index 0000000..44520d8 --- /dev/null +++ b/app/native/wndb/s21_times.py @@ -0,0 +1,112 @@ +from .database import * + +TIME_STATISTIC_NONE = 'NONE' +TIME_STATISTIC_AVERAGED = 'AVERAGED' +TIME_STATISTIC_MINIMUM = 'MINIMUM' +TIME_STATISTIC_MAXIMUM = 'MAXIMUM' +TIME_STATISTIC_RANGE = 'RANGE' + +element_schema = {'type': 'str' , 'optional': True , 'readonly': False} + +def get_time_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'DURATION' : element_schema, + 'HYDRAULIC TIMESTEP' : element_schema, + 'QUALITY TIMESTEP' : element_schema, + 'RULE TIMESTEP' : element_schema, + 'PATTERN TIMESTEP' : element_schema, + 'PATTERN START' : element_schema, + 'REPORT TIMESTEP' : element_schema, + 'REPORT START' : element_schema, + 'START CLOCKTIME' : element_schema, + 'STATISTIC' : element_schema} + + +def get_time(name: str) -> dict[str, Any]: + ts = read_all(name, f"select * from times") + d = {} + for e in ts: + d[e['key']] = str(e['value']) + return d + + +def _set_time(name: str, cs: ChangeSet) -> DbChangeSet: + raw_old = get_time(name) + + old = {} + new = {} + + new_dict = cs.operations[0] + schema = get_time_schema(name) + for key in schema.keys(): + if key in new_dict: + old[key] = str(raw_old[key]) + new[key] = str(new_dict[key]) + + redo_cs = g_update_prefix | { 'type' : 'time' } + + redo_sql = '' + for key, value in new.items(): + if redo_sql != '': + redo_sql += '\n' + redo_sql += f"update times set value = '{value}' where key = '{key}';" + redo_cs |= { key: value } + + undo_cs = g_update_prefix | { 'type' : 'time' } + + undo_sql = '' + for key, value in old.items(): + if undo_sql != '': + undo_sql += '\n' + undo_sql += f"update times set value = '{value}' where key = '{key}';" + undo_cs |= { key: value } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_time(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_time(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3] +# STATISTIC {NONE/AVERAGE/MIN/MAX/RANGE} +# DURATION value (units) +# HYDRAULIC TIMESTEP value (units) +# QUALITY TIMESTEP value (units) +# RULE TIMESTEP value (units) +# PATTERN TIMESTEP value (units) +# PATTERN START value (units) +# REPORT TIMESTEP value (units) +# REPORT START value (units) +# START CLOCKTIME value (AM PM) +# [EPA3] supports [EPA2] keyword +#-------------------------------------------------------------- + + +def inp_in_time(section: list[str]) -> str: + sql = '' + for s in section: + if s.startswith(';'): + continue + + line = s.upper().strip() + + # TOTAL DURATION => DURATION + if line.startswith('TOTAL DURATION'): + line = line.replace('TOTAL DURATION', 'DURATION') + + for key in get_time_schema('').keys(): + if line.startswith(key): + value = line.removeprefix(key).strip() + sql += f"update times set value = '{value}' where key = '{key}';" + return sql + + +def inp_out_time(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from times") + for obj in objs: + key = obj['key'] + value = obj['value'] + lines.append(f'{key} {value}') + return lines diff --git a/app/native/wndb/s22_report.py b/app/native/wndb/s22_report.py new file mode 100644 index 0000000..02b675b --- /dev/null +++ b/app/native/wndb/s22_report.py @@ -0,0 +1,34 @@ +from .database import * + + +#-------------------------------------------------------------- +# [EPA2] +# PAGE linesperpage +# STATUS {NONE/YES/FULL} +# SUMMARY {YES/NO} +# MESSAGES {YES/NO} +# ENERGY {NO/YES} +# NODES {NONE/ALL} +# NODES node1 node2 ... +# LINKS {NONE/ALL} +# LINKS link1 link2 ... +# FILE filename +# variable {YES/NO} +# variable {BELOW/ABOVE/PRECISION} value +# [EPA3][NOT SUPPORT] +# TRIALS {YES/NO} +#-------------------------------------------------------------- + + +def inp_in_report(section: list[str]) -> str: + return '' + + +def inp_out_report(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from report") + for obj in objs: + key = obj['key'] + value = obj['value'] + lines.append(f'{key} {value}') + return lines diff --git a/app/native/wndb/s23_options.py b/app/native/wndb/s23_options.py new file mode 100644 index 0000000..f1a372c --- /dev/null +++ b/app/native/wndb/s23_options.py @@ -0,0 +1,81 @@ +from .database import * +from .s23_options_util import get_option_schema, generate_v3 + + +def _inp_in_option(section: list[str]) -> ChangeSet: + if len(section) <= 0: + return ChangeSet() + + cs = g_update_prefix | { 'type' : 'option' } + for s in section: + if s.startswith(';'): + continue + + tokens = s.strip().split() + if tokens[0].upper() == 'PATTERN': # can not upper id + value = tokens[1] if len(tokens) > 1 else '' + cs |= { 'PATTERN' : value } + elif tokens[0].upper() == 'QUALITY': # can not upper trace node + value = tokens[1] if len(tokens) > 1 else '' + if len(tokens) > 2: + value += f' {tokens[2]}' + cs |= { 'QUALITY' : value } + else: + line = s.upper().strip() + for key in get_option_schema('').keys(): + if line.startswith(key): + value = line.removeprefix(key).strip() + cs |= { key : value } + + result = ChangeSet(cs) + result.merge(generate_v3(result)) + return result + + +def inp_in_option(section: list[str]) -> str: + sql = '' + result = _inp_in_option(section) + for op in result.operations: + for key in op.keys(): + if key == 'operation' or key == 'type': + continue + if op['type'] == 'option': + sql += f"update options set value = '{op[key]}' where key = '{key}';" + else: + sql += f"update options_v3 set value = '{op[key]}' where key = '{key}';" + return sql + + +def inp_out_option(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from options") + + is_dda = False + + for obj in objs: + if obj['key'] == 'DEMAND MODEL': + is_dda = obj['value'] == 'DDA' + + dda_ignore = [ + 'HEADERROR', # TODO: default is 0 which is conflict with PDA + 'FLOWCHANGE', # TODO: default is 0 which is conflict with PDA + 'MINIMUM PRESSURE', + 'REQUIRED PRESSURE', + 'PRESSURE EXPONENT' + ] + + for obj in objs: + key = obj['key'] + # why write this ? + if key == 'PRESSURE': + continue + # release version does not support new keys and has error message + if key == 'HTOL' or key == 'QTOL' or key == 'RQTOL': + continue + # ignore some weird settings for DDA + if is_dda and key in dda_ignore: + continue + value = obj['value'] + if str(value).strip() != '': + lines.append(f'{key} {value}') + return lines diff --git a/app/native/wndb/s23_options_util.py b/app/native/wndb/s23_options_util.py new file mode 100644 index 0000000..f273125 --- /dev/null +++ b/app/native/wndb/s23_options_util.py @@ -0,0 +1,401 @@ +from .database import * + + +#-------------------------------------------------------------- +# [EPANET2][IN][OUT] +# UNITS CFS/GPM/MGD/IMGD/AFD/LPS/LPM/MLD/CMH/CMD/SI +# PRESSURE PSI/KPA/M +# HEADLOSS H-W/D-W/C-M +# QUALITY NONE/AGE/TRACE/CHEMICAL (TraceNode) +# UNBALANCED STOP/CONTINUE {Niter} +# PATTERN id +# DEMAND MODEL DDA/PDA +# DEMAND MULTIPLIER value +# EMITTER EXPONENT value +# VISCOSITY value +# DIFFUSIVITY value +# SPECIFIC GRAVITY value +# TRIALS value +# ACCURACY value# +# HEADERROR value +# FLOWCHANGE value +# MINIMUM PRESSURE value +# REQUIRED PRESSURE value +# PRESSURE EXPONENT value# +# TOLERANCE value +# HTOL value +# QTOL value +# RQTOL value +# CHECKFREQ value +# MAXCHECK value +# DAMPLIMIT value +# ---- Unsupported Options ----- +# HYDRAULICS USE/SAVE filename +# MAP filename +#-------------------------------------------------------------- + + +element_schema = {'type': 'str' , 'optional': True , 'readonly': False} + + +OPTION_UNITS_CFS = 'CFS' +OPTION_UNITS_GPM = 'GPM' +OPTION_UNITS_MGD = 'MGD' +OPTION_UNITS_IMGD = 'IMGD' +OPTION_UNITS_AFD = 'AFD' +OPTION_UNITS_LPS = 'LPS' +OPTION_UNITS_LPM = 'LPM' +OPTION_UNITS_MLD = 'MLD' +OPTION_UNITS_CMH = 'CMH' +OPTION_UNITS_CMD = 'CMD' + +OPTION_PRESSURE_PSI = 'PSI' +OPTION_PRESSURE_KPA = 'KPA' +OPTION_PRESSURE_METERS = 'METERS' + +OPTION_HEADLOSS_HW = 'H-W' +OPTION_HEADLOSS_DW = 'D-W' +OPTION_HEADLOSS_CM = 'C-M' + +OPTION_UNBALANCED_STOP = 'STOP' +OPTION_UNBALANCED_CONTINUE = 'CONTINUE' + +OPTION_DEMAND_MODEL_DDA = 'DDA' +OPTION_DEMAND_MODEL_PDA = 'PDA' + +OPTION_QUALITY_NONE = 'NONE' +OPTION_QUALITY_CHEMICAL = 'CHEMICAL' +OPTION_QUALITY_AGE = 'AGE' +OPTION_QUALITY_TRACE = 'TRACE' + + +def get_option_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'UNITS' : element_schema, + 'PRESSURE' : element_schema, + 'HEADLOSS' : element_schema, + 'QUALITY' : element_schema, + 'UNBALANCED' : element_schema, + 'PATTERN' : element_schema, + 'DEMAND MODEL' : element_schema, + 'DEMAND MULTIPLIER' : element_schema, + 'EMITTER EXPONENT' : element_schema, + 'VISCOSITY' : element_schema, + 'DIFFUSIVITY' : element_schema, + 'SPECIFIC GRAVITY' : element_schema, + 'TRIALS' : element_schema, + 'ACCURACY' : element_schema, + 'HEADERROR' : element_schema, + 'FLOWCHANGE' : element_schema, + 'MINIMUM PRESSURE' : element_schema, + 'REQUIRED PRESSURE' : element_schema, + 'PRESSURE EXPONENT' : element_schema, + 'TOLERANCE' : element_schema, + 'HTOL' : element_schema, + 'QTOL' : element_schema, + 'RQTOL' : element_schema, + 'CHECKFREQ' : element_schema, + 'MAXCHECK' : element_schema, + 'DAMPLIMIT' : element_schema } + + +def get_option(name: str) -> dict[str, Any]: + ts = read_all(name, f"select * from options") + d = {} + for e in ts: + d[e['key']] = str(e['value']) + return d + + +def _set_option(name: str, cs: ChangeSet) -> DbChangeSet: + raw_old = get_option(name) + + old = {} + new = {} + + new_dict = cs.operations[0] + schema = get_option_schema(name) + for key in schema.keys(): + if key in new_dict: + old[key] = str(raw_old[key]) + new[key] = str(new_dict[key]) + + redo_cs = g_update_prefix | { 'type' : 'option' } + + redo_sql = '' + for key, value in new.items(): + if redo_sql != '': + redo_sql += '\n' + redo_sql += f"update options set value = '{value}' where key = '{key}';" + redo_cs |= { key: value } + + undo_cs = g_update_prefix | { 'type' : 'option' } + + undo_sql = '' + for key, value in old.items(): + if undo_sql != '': + undo_sql += '\n' + undo_sql += f"update options set value = '{value}' where key = '{key}';" + undo_cs |= { key: value } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_option(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_option(name, cs)) + + +OPTION_V3_FLOW_UNITS_CFS = OPTION_UNITS_CFS +OPTION_V3_FLOW_UNITS_GPM = OPTION_UNITS_GPM +OPTION_V3_FLOW_UNITS_MGD = OPTION_UNITS_MGD +OPTION_V3_FLOW_UNITS_IMGD = OPTION_UNITS_IMGD +OPTION_V3_FLOW_UNITS_AFD = OPTION_UNITS_AFD +OPTION_V3_FLOW_UNITS_LPS = OPTION_UNITS_LPS +OPTION_V3_FLOW_UNITS_LPM = OPTION_UNITS_LPM +OPTION_V3_FLOW_UNITS_MLD = OPTION_UNITS_MLD +OPTION_V3_FLOW_UNITS_CMH = OPTION_UNITS_CMH +OPTION_V3_FLOW_UNITS_CMD = OPTION_UNITS_CMD + +OPTION_V3_PRESSURE_UNITS_PSI = OPTION_PRESSURE_PSI +OPTION_V3_PRESSURE_UNITS_KPA = OPTION_PRESSURE_KPA +OPTION_V3_PRESSURE_UNITS_METERS = OPTION_PRESSURE_METERS + +OPTION_V3_HEADLOSS_MODEL_HW = OPTION_HEADLOSS_HW +OPTION_V3_HEADLOSS_MODEL_DW = OPTION_HEADLOSS_DW +OPTION_V3_HEADLOSS_MODEL_CM = OPTION_HEADLOSS_CM + +OPTION_V3_STEP_SIZING_FULL = 'FULL' +OPTION_V3_STEP_SIZING_RELAXATION = 'RELAXATION' +OPTION_V3_STEP_SIZING_LINESEARCH = 'LINESEARCH' + +OPTION_V3_IF_UNBALANCED_STOP = OPTION_UNBALANCED_STOP +OPTION_V3_IF_UNBALANCED_CONTINUE = OPTION_UNBALANCED_CONTINUE + +OPTION_V3_DEMAND_MODEL_FIXED = 'FIXED' +OPTION_V3_DEMAND_MODEL_CONSTRAINED = 'CONSTRAINED' +OPTION_V3_DEMAND_MODEL_POWER = 'POWER' +OPTION_V3_DEMAND_MODEL_LOGISTIC = 'LOGISTIC' + +OPTION_V3_LEAKAGE_MODEL_NONE = 'NONE' +OPTION_V3_LEAKAGE_MODEL_POWER = 'POWER' +OPTION_V3_LEAKAGE_MODEL_FAVAD = 'FAVAD' + +OPTION_V3_QUALITY_MODEL_NONE = OPTION_QUALITY_NONE +OPTION_V3_QUALITY_MODEL_CHEMICAL = OPTION_QUALITY_CHEMICAL +OPTION_V3_QUALITY_MODEL_AGE = OPTION_QUALITY_AGE +OPTION_V3_QUALITY_MODEL_TRACE = OPTION_QUALITY_TRACE + +OPTION_V3_QUALITY_UNITS_HRS = 'HRS' +OPTION_V3_QUALITY_UNITS_PCNT = 'PCNT' +OPTION_V3_QUALITY_UNITS_MGL = 'MG/L' +OPTION_V3_QUALITY_UNITS_UGL = 'UG/L' + + +def get_option_v3_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'FLOW_UNITS' : element_schema, + 'PRESSURE_UNITS' : element_schema, + 'HEADLOSS_MODEL' : element_schema, + 'SPECIFIC_GRAVITY' : element_schema, + 'SPECIFIC_VISCOSITY' : element_schema, + 'MAXIMUM_TRIALS' : element_schema, + 'HEAD_TOLERANCE' : element_schema, + 'FLOW_TOLERANCE' : element_schema, + 'FLOW_CHANGE_LIMIT' : element_schema, + 'RELATIVE_ACCURACY' : element_schema, + 'TIME_WEIGHT' : element_schema, + 'STEP_SIZING' : element_schema, + 'IF_UNBALANCED' : element_schema, + 'DEMAND_MODEL' : element_schema, + 'DEMAND_PATTERN' : element_schema, + 'DEMAND_MULTIPLIER' : element_schema, + 'MINIMUM_PRESSURE' : element_schema, + 'SERVICE_PRESSURE' : element_schema, + 'PRESSURE_EXPONENT' : element_schema, + 'LEAKAGE_MODEL' : element_schema, + 'LEAKAGE_COEFF1' : element_schema, + 'LEAKAGE_COEFF2' : element_schema, + 'EMITTER_EXPONENT' : element_schema, + 'QUALITY_MODEL' : element_schema, + 'QUALITY_NAME' : element_schema, + 'QUALITY_UNITS' : element_schema, + 'TRACE_NODE' : element_schema, + 'SPECIFIC_DIFFUSIVITY' : element_schema, + 'QUALITY_TOLERANCE' : element_schema } + + +def get_option_v3(name: str) -> dict[str, Any]: + ts = read_all(name, f"select * from options_v3") + d = {} + for e in ts: + d[e['key']] = str(e['value']) + return d + + +def _set_option_v3(name: str, cs: ChangeSet) -> DbChangeSet: + raw_old = get_option_v3(name) + + old = {} + new = {} + + new_dict = cs.operations[0] + schema = get_option_v3_schema(name) + for key in schema.keys(): + if key in new_dict: + old[key] = str(raw_old[key]) + new[key] = str(new_dict[key]) + + redo_cs = g_update_prefix | { 'type' : 'option_v3' } + + redo_sql = '' + for key, value in new.items(): + if redo_sql != '': + redo_sql += '\n' + redo_sql += f"update options_v3 set value = '{value}' where key = '{key}';" + redo_cs |= { key: value } + + undo_cs = g_update_prefix | { 'type' : 'option_v3' } + + undo_sql = '' + for key, value in old.items(): + if undo_sql != '': + undo_sql += '\n' + undo_sql += f"update options_v3 set value = '{value}' where key = '{key}';" + undo_cs |= { key: value } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_option_v3(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_option_v3(name, cs)) + + +_key_map_23 = { + 'UNITS' : 'FLOW_UNITS', + 'PRESSURE' : 'PRESSURE_UNITS', + 'HEADLOSS' : 'HEADLOSS_MODEL', + 'QUALITY' : 'QUALITY_MODEL', + 'UNBALANCED' : 'IF_UNBALANCED', + 'PATTERN' : 'DEMAND_PATTERN', + 'DEMAND MODEL' : 'DEMAND_MODEL', + 'DEMAND MULTIPLIER' : 'DEMAND_MULTIPLIER', + 'EMITTER EXPONENT' : 'EMITTER_EXPONENT', + 'VISCOSITY' : 'SPECIFIC_VISCOSITY', + 'DIFFUSIVITY' : 'SPECIFIC_DIFFUSIVITY', + 'SPECIFIC GRAVITY' : 'SPECIFIC_GRAVITY', + 'TRIALS' : 'MAXIMUM_TRIALS', + 'ACCURACY' : 'RELATIVE_ACCURACY', + #'HEADERROR' : '', + 'FLOWCHANGE' : 'FLOW_CHANGE_LIMIT', + 'MINIMUM PRESSURE' : 'MINIMUM_PRESSURE', + 'REQUIRED PRESSURE' : 'SERVICE_PRESSURE', + 'PRESSURE EXPONENT' : 'PRESSURE_EXPONENT', + 'TOLERANCE' : 'QUALITY_TOLERANCE', + 'HTOL' : 'HEAD_TOLERANCE', + 'QTOL' : 'FLOW_TOLERANCE', + #'RQTOL' : '', + #'CHECKFREQ' : '', + #'MAXCHECK' : '', + #'DAMPLIMIT' : '', +} + + +_key_map_32 = { + 'FLOW_UNITS' : 'UNITS', + 'PRESSURE_UNITS' : 'PRESSURE', + 'HEADLOSS_MODEL' : 'HEADLOSS', + 'SPECIFIC_GRAVITY' : 'SPECIFIC GRAVITY', + 'SPECIFIC_VISCOSITY' : 'VISCOSITY', + 'MAXIMUM_TRIALS' : 'TRIALS', + 'HEAD_TOLERANCE' : 'HTOL', + 'FLOW_TOLERANCE' : 'QTOL', + 'FLOW_CHANGE_LIMIT' : 'FLOWCHANGE', + 'RELATIVE_ACCURACY' : 'ACCURACY', + #'TIME_WEIGHT' : '', + #'STEP_SIZING' : '', + 'IF_UNBALANCED' : 'UNBALANCED', + 'DEMAND_MODEL' : 'DEMAND MODEL', + 'DEMAND_PATTERN' : 'PATTERN', + 'DEMAND_MULTIPLIER' : 'DEMAND MULTIPLIER', + 'MINIMUM_PRESSURE' : 'MINIMUM PRESSURE', + 'SERVICE_PRESSURE' : 'REQUIRED PRESSURE', + 'PRESSURE_EXPONENT' : 'PRESSURE EXPONENT', + #'LEAKAGE_MODEL' : '', + #'LEAKAGE_COEFF1' : '', + #'LEAKAGE_COEFF2' : '', + 'EMITTER_EXPONENT' : 'EMITTER EXPONENT', + 'QUALITY_MODEL' : 'QUALITY', + #'QUALITY_NAME' : '', + #'QUALITY_UNITS' : '', + #'TRACE_NODE' : '', + 'SPECIFIC_DIFFUSIVITY' : 'DIFFUSIVITY', + 'QUALITY_TOLERANCE' : 'TOLERANCE' +} + + +def generate_v2(cs: ChangeSet) -> ChangeSet: + op = cs.operations[0] + + if op['type'] == 'option': + return cs + + map = _key_map_32 + + cs_v2 = {} + for key in op: + if key == 'operation' or key == 'type': + continue + + if key in map.keys(): + if key != 'QUALITY_MODEL' and key != 'DEMAND_MODEL': + cs_v2 |= { map[key] : op[key] } + elif key == 'QUALITY_MODEL': + if str(op[key]).upper() == OPTION_QUALITY_TRACE and 'TRACE_NODE' in op.keys(): + cs_v2 |= { map[key] : f"{OPTION_QUALITY_TRACE} {op['TRACE_NODE']}" } + else: + cs_v2 |= { map[key] : str(op[key]).upper() } + elif key == 'DEMAND_MODEL': + if op[key] == OPTION_V3_DEMAND_MODEL_FIXED: + cs_v2 |= { map[key] : OPTION_DEMAND_MODEL_DDA } + else: + cs_v2 |= { map[key] : OPTION_DEMAND_MODEL_PDA } + + if len(cs_v2) > 0: + cs_v2 |= g_update_prefix | { 'type' : 'option' } + return ChangeSet(cs_v2) + + return ChangeSet() + + +def generate_v3(cs: ChangeSet) -> ChangeSet: + op = cs.operations[0] + + if op['type'] == 'option_v3': + return cs + + map = _key_map_23 + + cs_v3 = {} + for key in op: + if key == 'operation' or key == 'type': + continue + + if key in map.keys(): + if key != 'QUALITY' and key != 'DEMAND MODEL': + cs_v3 |= { map[key] : op[key] } + elif key == 'QUALITY': + tokens = str(op[key]).split() + if len(tokens) >= 1: + cs_v3 |= { map[key] : tokens[0].upper() } + if tokens[0].upper() == OPTION_QUALITY_TRACE and len(tokens) >= 2: + cs_v3 |= { 'TRACE_NODE' : tokens[1] } + elif key == 'DEMAND MODEL': + if op[key] == OPTION_DEMAND_MODEL_DDA: + cs_v3 |= { map[key] : OPTION_V3_DEMAND_MODEL_FIXED } + else: + cs_v3 |= { map[key] : OPTION_V3_DEMAND_MODEL_POWER } + + if len(cs_v3) > 0: + cs_v3 |= g_update_prefix | { 'type' : 'option_v3' } + return ChangeSet(cs_v3) + + return ChangeSet() + diff --git a/app/native/wndb/s23_options_v3.py b/app/native/wndb/s23_options_v3.py new file mode 100644 index 0000000..0a7738b --- /dev/null +++ b/app/native/wndb/s23_options_v3.py @@ -0,0 +1,79 @@ +from .database import * +from .s23_options_util import get_option_schema, get_option_v3_schema, generate_v2, generate_v3 + + +def _parse_v2(v2_lines: list[str]) -> dict[str, str]: + cs_v2 = g_update_prefix | { 'type' : 'option' } + for s in v2_lines: + tokens = s.split() + if tokens[0].upper() == 'PATTERN': # can not upper id + value = tokens[1] if len(tokens) > 1 else '' + cs_v2 |= { 'PATTERN' : value } + elif tokens[0].upper() == 'QUALITY': # can not upper trace node + value = tokens[1] + if len(tokens) > 2: + value += f' {tokens[2]}' + cs_v2 |= { 'QUALITY' : value } + else: + line = s.upper().strip() + for key in get_option_schema('').keys(): + if line.startswith(key): + value = line.removeprefix(key).strip() + cs_v2 |= { key : value } + return cs_v2 + + +def _inp_in_option_v3(section: list[str]) -> ChangeSet: + if len(section) <= 0: + return ChangeSet() + + cs_v3 = g_update_prefix | { 'type' : 'option_v3' } + v2_lines = [] + for s in section: + if s.startswith(';'): + continue + + tokens = s.strip().split() + key = tokens[0] + if key in get_option_v3_schema('').keys(): + value = '' + if len(tokens) == 2: + value = tokens[1] + elif len(tokens) > 2: + value = ' '.join(tokens[1:]) + cs_v3 |= { key : value } + else: + v2_lines.append(s.strip()) + + # unlikely... + cs_v2 = _parse_v2(v2_lines) + + result = ChangeSet(cs_v3) + result.merge(generate_v3(ChangeSet(cs_v2))) + result.merge(generate_v2(result)) + return result + + +def inp_in_option_v3(section: list[str]) -> str: + sql = '' + result = _inp_in_option_v3(section) + for op in result.operations: + for key in op.keys(): + if key == 'operation' or key == 'type': + continue + if op['type'] == 'option_v3': + sql += f"update options_v3 set value = '{op[key]}' where key = '{key}';" + else: + sql += f"update options set value = '{op[key]}' where key = '{key}';" + return sql + + +def inp_out_option_v3(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from options_v3") + for obj in objs: + key = obj['key'] + value = obj['value'] + if str(value).strip() != '': + lines.append(f'{key} {value}') + return lines diff --git a/app/native/wndb/s24_coordinates.py b/app/native/wndb/s24_coordinates.py new file mode 100644 index 0000000..d038a96 --- /dev/null +++ b/app/native/wndb/s24_coordinates.py @@ -0,0 +1,92 @@ +from .database import * +from .s0_base import get_link_nodes + +def sql_update_coord(node: str, x: float, y: float) -> str: + coord = f"st_geomfromtext('point({x} {y})')" + return str(f"update coordinates set coord = {coord} where node = '{node}';") + + +def sql_insert_coord(node: str, x: float, y: float) -> str: + coord = f"st_geomfromtext('point({x} {y})')" + return str(f"insert into coordinates (node, coord) values ('{node}', {coord});") + + +def sql_delete_coord(node: str) -> str: + return str(f"delete from coordinates where node = '{node}';") + + +def from_postgis_point(coord: str) -> dict[str, float]: + xy = coord.lower().removeprefix('point(').removesuffix(')').split(' ') + return { 'x': float(xy[0]), 'y': float(xy[1]) } + + +def get_node_coord(name: str, node: str) -> dict[str, float]: + row = try_read(name, f"select st_astext(coord) as coord_geom from coordinates where node = '{node}'") + if row == None: + write(name, sql_insert_coord(node, 0.0, 0.0)) + return {'x': 0.0, 'y': 0.0} + return from_postgis_point(row['coord_geom']) + +# DingZQ 2025-01-03, get nodes in extent +# return node id list +# node_id:junction:x:y +def get_nodes_in_extent(name: str, x1: float, y1: float, x2: float, y2: float) -> list[str]: + nodes = [] + objs = read_all(name, 'select node, st_astext(coord) as coord_geom from coordinates') + for obj in objs: + node_id = obj['node'] + coord = from_postgis_point(obj['coord_geom']) + x = coord['x'] + y = coord['y'] + if x1 <= x <= x2 and y1 <= y <= y2: + nodes.append(f"{node_id}:junction:{x}:{y}") + return nodes + +# DingZQ 2025-01-03, get links in extent +# return link id list +# link_id:pipe:node_id1:node_id2 +def get_links_in_extent(name: str, x1: float, y1: float, x2: float, y2: float) -> list[str]: + node_ids = set([s.split(':')[0] for s in get_nodes_in_extent(name, x1, y1, x2, y2)]) + + all_link_ids = [] + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select id from pipes") + for record in cur: + all_link_ids.append(record['id']) + + links = [] + for link_id in all_link_ids: + nodes = get_link_nodes(name, link_id) + if nodes[0] in node_ids and nodes[1] in node_ids: + links.append(f"{link_id}:pipe:{nodes[0]}:{nodes[1]}") + return links + + +def node_has_coord(name: str, node: str) -> bool: + return try_read(name, f"select node from coordinates where node = '{node}'") != None + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# id x y +#-------------------------------------------------------------- +# exception ! need merge to node change set ! + + +def inp_in_coord(line: str) -> str: + tokens = line.split() + node = tokens[0] + coord = f"st_geomfromtext('point({tokens[1]} {tokens[2]})')" + return str(f"insert into coordinates (node, coord) values ('{node}', {coord});") + + +def inp_out_coord(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select node, st_astext(coord) as coord_geom from coordinates') + for obj in objs: + node = obj['node'] + coord = from_postgis_point(obj['coord_geom']) + x = coord['x'] + y = coord['y'] + lines.append(f'{node} {x} {y}') + return lines diff --git a/app/native/wndb/s25_vertices.py b/app/native/wndb/s25_vertices.py new file mode 100644 index 0000000..0bd7647 --- /dev/null +++ b/app/native/wndb/s25_vertices.py @@ -0,0 +1,120 @@ +from .database import * + + +def get_vertex_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'link' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'coords' : {'type': 'list' , 'optional': False , 'readonly': False, + 'element': { 'x' : {'type': 'float' , 'optional': False , 'readonly': False }, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False } }}} + + +def get_vertex(name: str, link: str) -> dict[str, Any]: + cus = read_all(name, f"select * from vertices where link = '{link}' order by _order") + cs = [] + for r in cus: + cs.append({ 'x': float(r['x']), 'y': float(r['y']) }) + return { 'link': link, 'coords': cs } + + +def _set_vertex(name: str, cs: ChangeSet) -> DbChangeSet: + link = cs.operations[0]['link'] + + old = get_vertex(name, link) + new = { 'link': link, 'coords': [] } + + f_link = f"'{link}'" + + # TODO: transaction ? + redo_sql = f"delete from vertices where link = {f_link};" + for xy in cs.operations[0]['coords']: + x, y = float(xy['x']), float(xy['y']) + f_x, f_y = x, y + redo_sql += f"\ninsert into vertices (link, x, y) values ({f_link}, {f_x}, {f_y});" + new['coords'].append({ 'x': x, 'y': y }) + + undo_sql = f"delete from vertices where link = {f_link};" + for xy in old['coords']: + f_x, f_y = xy['x'], xy['y'] + undo_sql += f"\ninsert into vertices (link, x, y) values ({f_link}, {f_x}, {f_y});" + + redo_cs = { 'type': 'vertex' } | new + undo_cs = { 'type': 'vertex' } | old + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_vertex(name: str, cs: ChangeSet) -> ChangeSet: + result = _set_vertex(name, cs) + result.redo_cs[0] |= g_update_prefix + result.undo_cs[0] |= g_update_prefix + return execute_command(name, result) + + +def _add_vertex(name: str, cs: ChangeSet) -> DbChangeSet: + result = _set_vertex(name, cs) + result.redo_cs[0] |= g_add_prefix + result.undo_cs[0] |= g_delete_prefix + return result + + +def _delete_vertex(name: str, cs: ChangeSet) -> DbChangeSet: + cs.operations[0]['coords'] = [] + result = _set_vertex(name, cs) + result.redo_cs[0] |= g_delete_prefix + result.undo_cs[0] |= g_add_prefix + return result + + +def add_vertex(name: str, cs: ChangeSet) -> ChangeSet: + result = _add_vertex(name, cs) + return execute_command(name, result) + + +def delete_vertex(name: str, cs: ChangeSet) -> ChangeSet: + result = _delete_vertex(name, cs) + return execute_command(name, result) + + +def get_all_vertex_links(name: str) -> list[str]: + result : list[str] = [] + rows = read_all(name, 'select link from vertices order by link') + for row in rows: + result.append(str(row['link'])) + return result + + +def get_all_vertices(name: str) -> list[dict[str, Any]]: + return read_all(name, 'select * from vertices order by link') + + +#-------------------------------------------------------------- +# [EPA2][IN][OUT] +# id x y +# [EPA3][NOT SUPPORT] +#-------------------------------------------------------------- + + +def inp_in_vertex(line: str) -> str: + tokens = line.split() + link = tokens[0] + x = float(tokens[1]) + y = float(tokens[2]) + return str(f"insert into vertices (link, x, y) values ('{link}', {x}, {y});") + + +def inp_out_vertex(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from vertices order by _order") + for obj in objs: + link = obj['link'] + x = obj['x'] + y = obj['y'] + lines.append(f"{link} {x} {y}") + return lines + + +def delete_vertex_by_link(name: str, link: str) -> ChangeSet: + row = try_read(name, f"select * from vertices where link = '{link}'") + if row == None: + return ChangeSet() + return ChangeSet(g_delete_prefix | {'type': 'vertex', 'link' : link}) diff --git a/app/native/wndb/s26_labels.py b/app/native/wndb/s26_labels.py new file mode 100644 index 0000000..3bb0596 --- /dev/null +++ b/app/native/wndb/s26_labels.py @@ -0,0 +1,137 @@ +from .database import * + + +def get_label_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'x' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'label' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'node' : {'type': 'str' , 'optional': True , 'readonly': False} } + + +def get_label(name: str, x: float, y: float) -> dict[str, Any]: + d = {} + d['x'] = x + d['y'] = y + l = try_read(name, f'select * from labels where x = {x} and y = {y}') + if l == None: + d['label'] = None + d['node'] = None + else: + d['label'] = str(l['label']) + d['node'] = str(l['node']) if l['node'] != None else None + return d + + +class Label(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'label' + self.x = float(input['x']) + self.y = float(input['y']) + self.label = str(input['label']) + self.node = str(input['node']) if 'node' in input and input['node'] != None else None + + self.f_type = f"'{self.type}'" + self.f_x = self.x + self.f_y = self.y + self.f_label = f"'{self.label}'" + self.f_node = f"'{self.node}'" if self.node != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'x': self.x, 'y': self.y, 'label': self.label, 'node': self.node } + + def as_xy_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'x': self.x, 'y': self.y } + + +def _set_label(name: str, cs: ChangeSet) -> DbChangeSet: + old = Label(get_label(name, cs.operations[0]['x'], cs.operations[0]['y'])) + raw_new = get_label(name, cs.operations[0]['x'], cs.operations[0]['y']) + + new_dict = cs.operations[0] + schema = get_label_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Label(raw_new) + + redo_sql = f"update labels set label = {new.f_label}, node = {new.f_node} where x = {new.f_x} and y = {new.f_y};" + undo_sql = f"update labels set label = {old.f_label}, node = {old.f_node} where x = {old.f_x} and y = {old.f_y};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_label(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_label(name, cs)) + + +def _add_label(name: str, cs: ChangeSet) -> DbChangeSet: + new = Label(cs.operations[0]) + + redo_sql = f"insert into labels (x, y, label, node) values ({new.f_x}, {new.f_y}, {new.f_label}, {new.f_node});" + undo_sql = f"delete from labels where x = {new.f_x} and y = {new.f_y};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_xy_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_label(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _add_label(name, cs)) + + +def _delete_label(name: str, cs: ChangeSet) -> DbChangeSet: + old = Label(get_label(name, cs.operations[0]['x'], cs.operations[0]['y'])) + + redo_sql = f"delete from labels where x = {old.f_x} and y = {old.f_y};" + undo_sql = f"insert into labels (x, y, label, node) values ({old.f_x}, {old.f_y}, {old.f_label}, {old.f_node});" + + redo_cs = g_delete_prefix | old.as_xy_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_label(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _delete_label(name, cs)) + + +def inp_in_label(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + x = float(tokens[0]) + y = float(tokens[1]) + label = str(tokens[2]) + node = str(tokens[3]) if num >= 4 else None + node = f"'{node}'" if node != None else 'null' + + return str(f"insert into labels (x, y, label, node) values ({x}, {y}, '{label}', {node});") + + +def inp_out_label(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from labels') + for obj in objs: + x = obj['x'] + y = obj['y'] + label = obj['label'] + node = obj['node'] if obj['node'] != None else '' + lines.append(f'{x} {y} {label} {node}') + return lines + + +def unset_label_by_node(name: str, node: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select x, y from labels where node = '{node}'") + for row in rows: + cs.append(g_update_prefix | {'type': 'label', 'x': row['x'], 'y': row['y'], 'node': None}) + + return cs diff --git a/app/native/wndb/s27_backdrop.py b/app/native/wndb/s27_backdrop.py new file mode 100644 index 0000000..bedc8fa --- /dev/null +++ b/app/native/wndb/s27_backdrop.py @@ -0,0 +1,39 @@ +from .database import * + + +def get_backdrop_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'content' : {'type': 'str' , 'optional': False , 'readonly': False} } + + +def get_backdrop(name: str) -> dict[str, Any]: + e = read(name, f"select * from backdrop") + return { 'content': e['content'] } + + +def _set_backdrop(name: str, cs: ChangeSet) -> DbChangeSet: + old = get_backdrop(name) + + redo_sql = f"update backdrop set content = '{cs.operations[0]['content']}' where content = '{old['content']}';" + undo_sql = f"update backdrop set content = '{old['content']}' where content = '{cs.operations[0]['content']}';" + + redo_cs = g_update_prefix | { 'type': 'backdrop', 'content': cs.operations[0]['content'] } + undo_cs = g_update_prefix | { 'type': 'backdrop', 'content': old['content'] } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_backdrop(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_backdrop(name, cs)) + + +def inp_in_backdrop(section: list[str]) -> str: + if section == []: + return str('') + + content = '\n'.join(section) + return str(f"update backdrop set content = '{content}';") + + +def inp_out_backdrop(name: str) -> list[str]: + obj = str(get_backdrop(name)['content']) + return obj.split('\n') \ No newline at end of file diff --git a/app/native/wndb/s28_end.py b/app/native/wndb/s28_end.py new file mode 100644 index 0000000..e69de29 diff --git a/app/native/wndb/s29_scada_device.py b/app/native/wndb/s29_scada_device.py new file mode 100644 index 0000000..7af8ee0 --- /dev/null +++ b/app/native/wndb/s29_scada_device.py @@ -0,0 +1,123 @@ +from .database import * + + +SCADA_DEVICE_TYPE_PRESSURE = 'PRESSURE' +SCADA_DEVICE_TYPE_DEMAND = 'DEMAND' +SCADA_DEVICE_TYPE_QUALITY = 'QUALITY' +SCADA_DEVICE_TYPE_LEVEL = 'LEVEL' +SCADA_DEVICE_TYPE_FLOW = 'FLOW' +SCADA_DEVICE_TYPE_UNKNOWN = 'UNKNOWN' + + +def get_scada_device_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str', 'optional': False, 'readonly': True }, + 'name' : {'type': 'str', 'optional': True , 'readonly': False}, + 'address': {'type': 'str', 'optional': True , 'readonly': False}, + 'sd_type': {'type': 'str', 'optional': True , 'readonly': False}} + + +def get_scada_device(name: str, id: str) -> dict[str, Any]: + sm = try_read(name, f"select * from scada_device where id = '{id}'") + if sm == None: + return {} + d = {} + d['id'] = str(sm['id']) + d['name'] = str(sm['name']) if sm['name'] != None else None + d['address'] = str(sm['address']) if sm['address'] != None else None + d['sd_type'] = str(sm['sd_type']) if sm['sd_type'] != None else None + return d + + +class ScadaDevice(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'scada_device' + self.id = str(input['id']) + self.name = str(input['name']) if 'name' in input and input['name'] != None else None + self.address = str(input['address']) if 'address' in input and input['address'] != None else None + self.sd_type = str(input['sd_type']) if 'sd_type' in input and input['sd_type'] != None else None + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_name = f"'{self.name}'" if self.name != None else 'null' + self.f_address = f"'{self.address}'" if self.address != None else 'null' + self.f_sd_type = f"'{self.sd_type}'" if self.sd_type != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'name': self.name, 'address': self.address, 'sd_type': self.sd_type } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_scada_device(name: str, cs: ChangeSet) -> DbChangeSet: + old = ScadaDevice(get_scada_device(name, cs.operations[0]['id'])) + raw_new = get_scada_device(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_scada_device_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = ScadaDevice(raw_new) + + redo_sql = f"update scada_device set name = {new.f_name}, address = {new.f_address}, sd_type = {new.f_sd_type} where id = {new.f_id};" + undo_sql = f"update scada_device set name = {old.f_name}, address = {old.f_address}, sd_type = {old.f_sd_type} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_scada_device(name: str, cs: ChangeSet) -> ChangeSet: + if get_scada_device(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_scada_device(name, cs), False) + + +def _add_scada_device(name: str, cs: ChangeSet) -> DbChangeSet: + new = ScadaDevice(cs.operations[0]) + + redo_sql = f"insert into scada_device (id, name, address, sd_type) values ({new.f_id}, {new.f_name}, {new.f_address}, {new.f_sd_type});" + undo_sql = f"delete from scada_device where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_scada_device(name: str, cs: ChangeSet) -> ChangeSet: + if get_scada_device(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_scada_device(name, cs), False) + + +def _delete_scada_device(name: str, cs: ChangeSet) -> DbChangeSet: + old = ScadaDevice(get_scada_device(name, cs.operations[0]['id'])) + + redo_sql = f"delete from scada_device where id = {old.f_id};" + undo_sql = f"insert into scada_device (id, name, address, sd_type) values ({old.f_id}, {old.f_name}, {old.f_address}, {old.f_sd_type});" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_scada_device(name: str, cs: ChangeSet) -> ChangeSet: + if get_scada_device(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_scada_device(name, cs), False) + + +def get_all_scada_device_ids(name: str) -> list[str]: + result : list[str] = [] + rows = read_all(name, 'select id from scada_device order by id') + for row in rows: + result.append(str(row['id'])) + return result + + +def get_all_scada_devices(name: str) -> list[dict[str, Any]]: + return read_all(name, 'select * from scada_device order by id') diff --git a/app/native/wndb/s2_junctions.py b/app/native/wndb/s2_junctions.py new file mode 100644 index 0000000..9007229 --- /dev/null +++ b/app/native/wndb/s2_junctions.py @@ -0,0 +1,191 @@ +from .database import * +from .s0_base import * +from .s24_coordinates import * + + +def get_junction_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'x' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'elevation' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'links' : {'type': 'str_list' , 'optional': False , 'readonly': True } } + + +def get_junction(name: str, id: str) -> dict[str, Any]: + j = try_read(name, f"select * from junctions where id = '{id}'") + if j == None: + return {} + xy = get_node_coord(name, id) + d = {} + d['id'] = str(j['id']) + d['x'] = float(xy['x']) + d['y'] = float(xy['y']) + d['elevation'] = float(j['elevation']) + d['links'] = get_node_links(name, id) + return d + +# DingZQ, 2025-03-29 +def get_all_junctions(name: str) -> list[dict[str, Any]]: + rows = read_all(name, f"select * from junctions") + if rows == None: + return [] + + result = [] + for row in rows: + d = {} + id = str(row['id']) + xy = get_node_coord(name, id) + d['id'] = id + d['x'] = float(xy['x']) + d['y'] = float(xy['y']) + d['elevation'] = float(row['elevation']) + d['links'] = get_node_links(name, id) + result.append(d) + + return result + +class Junction(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'junction' + self.id = str(input['id']) + self.x = float(input['x']) + self.y = float(input['y']) + self.elevation = float(input['elevation']) + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_elevation = self.elevation + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'x': self.x, 'y': self.y, 'elevation': self.elevation } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_junction(name: str, cs: ChangeSet) -> DbChangeSet: + old = Junction(get_junction(name, cs.operations[0]['id'])) + raw_new = get_junction(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_junction_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Junction(raw_new) + + redo_sql = f"update junctions set elevation = {new.f_elevation} where id = {new.f_id};" + redo_sql += f"\n{sql_update_coord(new.id, new.x, new.y)}" + + undo_sql = sql_update_coord(old.id, old.x, old.y) + undo_sql += f"\nupdate junctions set elevation = {old.f_elevation} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_junction(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_junction(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_junction(name, cs)) + + +def _add_junction(name: str, cs: ChangeSet) -> DbChangeSet: + new = Junction(cs.operations[0]) + + redo_sql = f"insert into _node (id, type) values ({new.f_id}, {new.f_type});" + redo_sql += f"\ninsert into junctions (id, elevation) values ({new.f_id}, {new.f_elevation});" + redo_sql += f"\n{sql_insert_coord(new.id, new.x, new.y)}" + + undo_sql = sql_delete_coord(new.id) + undo_sql += f"\ndelete from junctions where id = {new.f_id};" + undo_sql += f"\ndelete from _node where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_junction(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_junction(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_junction(name, cs)) + + +def _delete_junction(name: str, cs: ChangeSet) -> DbChangeSet: + old = Junction(get_junction(name, cs.operations[0]['id'])) + + redo_sql = sql_delete_coord(old.id) + redo_sql += f"\ndelete from junctions where id = {old.f_id};" + redo_sql += f"\ndelete from _node where id = {old.f_id};" + + undo_sql = f"insert into _node (id, type) values ({old.f_id}, {old.f_type});" + undo_sql += f"\ninsert into junctions (id, elevation) values ({old.f_id}, {old.f_elevation});" + undo_sql += f"\n{sql_insert_coord(old.id, old.x, old.y)}" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_junction(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_junction(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_junction(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2] +# [IN] +# id elev. (demand) (demand pattern) ;desc +# [OUT] +# id elev. ;desc +#-------------------------------------------------------------- +# [EPA3] +# [IN] +# id elev. (demand) (demand pattern) +# [OUT] +# id elev. * * minpressure fullpressure +#-------------------------------------------------------------- + + +def inp_in_junction(line: str, demand_outside: bool) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + id = str(tokens[0]) + elevation = float(tokens[1]) + demand = float(tokens[2]) if num_without_desc >= 3 and tokens[2] != '*' else None + pattern = str(tokens[3]) if num_without_desc >= 4 and tokens[3] != '*' else None + pattern = f"'{pattern}'" if pattern != None else 'null' + desc = str(tokens[-1]) if has_desc else None + + sql = f"insert into _node (id, type) values ('{id}', 'junction');insert into junctions (id, elevation) values ('{id}', {elevation});" + if demand != None and demand_outside == False: + sql += f"insert into demands (junction, demand, pattern) values ('{id}', {demand}, {pattern});" + + return str(sql) + + +def inp_out_junction(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from junctions') + for obj in objs: + id = obj['id'] + elev = obj['elevation'] + desc = ';' + lines.append(f'{id} {elev} {desc}') + return lines diff --git a/app/native/wndb/s30_scada_device_data.py b/app/native/wndb/s30_scada_device_data.py new file mode 100644 index 0000000..d1a6043 --- /dev/null +++ b/app/native/wndb/s30_scada_device_data.py @@ -0,0 +1,90 @@ +from .database import * + + +def get_scada_device_data_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'device_id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'data' : {'type': 'list' , 'optional': False , 'readonly': False, + 'element': { 'time' : {'type': 'str' , 'optional': False , 'readonly': False }, + 'value' : {'type': 'float' , 'optional': False , 'readonly': False } }}} + + +def get_scada_device_data(name: str, device_id: str) -> dict[str, Any]: + sds = read_all(name, f"select * from scada_device_data where device_id = '{device_id}' order by time") + ds = [] + for r in sds: + ds.append({ 'time': str(r['time']), 'value': float(r['value']) }) + return { 'device_id': device_id, 'data': ds } + + +def _set_scada_device_data(name: str, cs: ChangeSet) -> DbChangeSet: + device_id = cs.operations[0]['device_id'] + + old = get_scada_device_data(name, device_id) + new = { 'device_id': device_id, 'data': [] } + + f_device_id = f"'{device_id}'" + + # TODO: transaction ? + redo_sql = f"delete from scada_device_data where device_id = {f_device_id};" + for tv in cs.operations[0]['data']: + time, value = str(tv['time']), float(tv['value']) + f_time, f_value = f"'{time}'", value + redo_sql += f"\ninsert into scada_device_data (device_id, time, value) values ({f_device_id}, {f_time}, {f_value});" + new['data'].append({ 'time': time, 'value': value }) + + undo_sql = f"delete from scada_device_data where device_id = {f_device_id};" + for tv in old['data']: + time, value = str(tv['time']), float(tv['value']) + f_time, f_value = f"'{time}'", value + undo_sql += f"\ninsert into scada_device_data (device_id, time, value) values ({f_device_id}, {f_time}, {f_value});" + + redo_cs = g_update_prefix | { 'type': 'scada_device_data' } | new + undo_cs = g_update_prefix | { 'type': 'scada_device_data' } | old + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_scada_device_data(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_scada_device_data(name, cs), False) + + +def _add_scada_device_data(name: str, cs: ChangeSet) -> DbChangeSet: + values = cs.operations[0] + device_id = values['device_id'] + time = values['time'] + value = float(values['value']) + + redo_sql = f"insert into scada_device_data (device_id, time, value) values ('{device_id}', '{time}', {value});" + undo_sql = f"delete from scada_device_data where device_id = '{device_id}' and time = '{time}';" + redo_cs = g_add_prefix | { 'type': 'scada_device_data', 'device_id': device_id, 'time': time, 'value': value } + undo_cs = g_delete_prefix | { 'type': 'scada_device_data', 'device_id': device_id, 'time': time } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_scada_device_data(name: str, cs: ChangeSet) -> ChangeSet: + row = try_read(name, f"select * from scada_device_data where device_id = '{cs.operations[0]['device_id']}' and time = '{cs.operations[0]['time']}'") + if row != None: + return ChangeSet() + return execute_command(name, _add_scada_device_data(name, cs), False) + + +def _delete_scada_device_data(name: str, cs: ChangeSet) -> DbChangeSet: + values = cs.operations[0] + device_id = values['device_id'] + time = values['time'] + value = float(read(name, f"select * from scada_device_data where device_id = '{device_id}' and time = '{time}'")['value']) + + redo_sql = f"delete from scada_device_data where device_id = '{device_id}' and time = '{time}';" + undo_sql = f"insert into scada_device_data (device_id, time, value) values ('{device_id}', '{time}', {value});" + redo_cs = g_delete_prefix | { 'type': 'scada_device_data', 'device_id': device_id, 'time': time } + undo_cs = g_add_prefix | { 'type': 'scada_device_data', 'device_id': device_id, 'time': time, 'value': value } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_scada_device_data(name: str, cs: ChangeSet) -> ChangeSet: + row = try_read(name, f"select * from scada_device_data where device_id = '{cs.operations[0]['device_id']}' and time = '{cs.operations[0]['time']}'") + if row == None: + return ChangeSet() + return execute_command(name, _delete_scada_device_data(name, cs), False) diff --git a/app/native/wndb/s31_scada_element.py b/app/native/wndb/s31_scada_element.py new file mode 100644 index 0000000..457def3 --- /dev/null +++ b/app/native/wndb/s31_scada_element.py @@ -0,0 +1,197 @@ +from .database import * +from .s0_base import * + + +SCADA_TYPE_PRESSURE = 'PRESSURE' +SCADA_TYPE_DEMAND = 'DEMAND' +SCADA_TYPE_QUALITY = 'QUALITY' +SCADA_TYPE_LEVEL = 'LEVEL' +SCADA_TYPE_FLOW = 'FLOW' + + +SCADA_MODEL_TYPE_JUNCTION = 'JUNCTION' +SCADA_MODEL_TYPE_RESERVOIR = 'RESERVOIR' +SCADA_MODEL_TYPE_TANK = 'TANK' +SCADA_MODEL_TYPE_PIPE = 'PIPE' +SCADA_MODEL_TYPE_PUMP = 'PUMP' +SCADA_MODEL_TYPE_VALVE = 'VALVE' + + +SCADA_ELEMENT_STATUS_OFFLINE = 'OFF' +SCADA_ELEMENT_STATUS_ONLINE = 'ON' + + +_scada_model_types = [SCADA_MODEL_TYPE_JUNCTION, SCADA_MODEL_TYPE_RESERVOIR, SCADA_MODEL_TYPE_TANK, SCADA_MODEL_TYPE_PIPE, SCADA_MODEL_TYPE_PUMP, SCADA_MODEL_TYPE_VALVE] + + +def _check_model(name: str, cs: ChangeSet) -> bool: + has_model_id = 'model_id' in cs.operations[0] + has_model_type = 'model_type' in cs.operations[0] + + if has_model_id and has_model_type: + pass + elif has_model_id and not has_model_type: + return False + elif not has_model_id and has_model_type: + return False + elif not has_model_id and not has_model_type: + return True + + _model_id = cs.operations[0]['model_id'] + _model_type = cs.operations[0]['model_type'] + if _model_type == SCADA_MODEL_TYPE_JUNCTION: + return is_junction(name, _model_id) + elif _model_type == SCADA_MODEL_TYPE_RESERVOIR: + return is_reservoir(name, _model_id) + elif _model_type == SCADA_MODEL_TYPE_TANK: + return is_tank(name, _model_id) + elif _model_type == SCADA_MODEL_TYPE_PIPE: + return is_pipe(name, _model_id) + elif _model_type == SCADA_MODEL_TYPE_PUMP: + return is_pump(name, _model_id) + elif _model_type == SCADA_MODEL_TYPE_VALVE: + return is_valve(name, _model_id) + return False + + +def get_scada_element_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'x' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'device_id' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'model_id' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'model_type' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'status' : {'type': 'str' , 'optional': True , 'readonly': False} } + + +def get_scada_element(name: str, id: str) -> dict[str, Any]: + sm = try_read(name, f"select * from scada_element where id = '{id}'") + if sm == None: + return {} + d = {} + d['id'] = str(sm['id']) + d['x'] = float(sm['x']) + d['y'] = float(sm['y']) + d['device_id'] = str(sm['device_id']) if sm['device_id'] != None else None + d['model_id'] = str(sm['model_id']) if sm['model_id'] != None else None + d['model_type'] = str(sm['model_type']) if sm['model_type'] != None else None + d['status'] = str(sm['status']) + return d + + +class ScadaModel(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'scada_element' + self.id = str(input['id']) + self.x = float(input['x']) + self.y = float(input['y']) + self.device_id = str(input['device_id']) if 'device_id' in input and input['device_id'] != None else None + self.model_id = str(input['model_id']) if 'model_id' in input and input['model_id'] != None else None + self.model_type = str(input['model_type']) if 'model_type' in input and input['model_type'] != None else None + self.status = str(input['status']) if 'status' in input and input['status'] != None else SCADA_ELEMENT_STATUS_OFFLINE + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_x = self.x + self.f_y = self.y + self.f_device_id = f"'{self.device_id}'" if self.device_id != None else 'null' + self.f_model_id = f"'{self.model_id}'" if self.model_id != None else 'null' + self.f_model_type = f"'{self.model_type}'" if self.model_type != None else 'null' + self.f_status = f"'{self.status}'" + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'x': self.x, 'y': self.y, 'device_id': self.device_id, 'model_id': self.model_id, 'model_type': self.model_type, 'status': self.status } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_scada_element(name: str, cs: ChangeSet) -> DbChangeSet: + old = ScadaModel(get_scada_element(name, cs.operations[0]['id'])) + raw_new = get_scada_element(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_scada_element_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = ScadaModel(raw_new) + + redo_sql = f"update scada_element set x = {new.f_x}, y = {new.f_y}, device_id = {new.f_device_id}, model_id = {new.f_model_id}, model_type = {new.f_model_type}, status = {new.f_status} where id = {new.f_id};" + undo_sql = f"update scada_element set x = {old.f_x}, y = {old.f_y}, device_id = {old.f_device_id}, model_id = {old.f_model_id}, model_type = {old.f_model_type}, status = {old.f_status} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_scada_element(name: str, cs: ChangeSet) -> ChangeSet: + if get_scada_element(name, cs.operations[0]['id']) == {}: + return ChangeSet() + if _check_model(name, cs) == False: + return ChangeSet() + return execute_command(name, _set_scada_element(name, cs)) + + +def _add_scada_element(name: str, cs: ChangeSet) -> DbChangeSet: + new = ScadaModel(cs.operations[0]) + + redo_sql = f"insert into scada_element (id, x, y, device_id, model_id, model_type, status) values ({new.f_id}, {new.f_x}, {new.f_y}, {new.f_device_id}, {new.f_model_id}, {new.f_model_type}, {new.f_status});" + undo_sql = f"delete from scada_element where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_scada_element(name: str, cs: ChangeSet) -> ChangeSet: + if get_scada_element(name, cs.operations[0]['id']) != {}: + return ChangeSet() + if _check_model(name, cs) == False: + return ChangeSet() + return execute_command(name, _add_scada_element(name, cs)) + + +def _delete_scada_element(name: str, cs: ChangeSet) -> DbChangeSet: + old = ScadaModel(get_scada_element(name, cs.operations[0]['id'])) + + redo_sql = f"delete from scada_element where id = {old.f_id};" + undo_sql = f"insert into scada_element (id, x, y, device_id, model_id, model_type, status) values ({old.f_id}, {old.f_x}, {old.f_y}, {old.f_device_id}, {old.f_model_id}, {old.f_model_type}, {old.f_status});" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_scada_element(name: str, cs: ChangeSet) -> ChangeSet: + if get_scada_element(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_scada_element(name, cs)) + + +def get_all_scada_element_ids(name: str) -> list[str]: + result : list[str] = [] + rows = read_all(name, 'select id from scada_element order by id') + for row in rows: + result.append(str(row['id'])) + return result + +# +# create table scada_element +# ( +# id text primary key +# , x float8 not null +# , y float8 not null +# , device_id text references scada_device(id) +# , model_id varchar(32) -- add constraint in API +# , model_type scada_model_type +# , status scada_element_status not null default 'OFF' +# ); +# +# 返回list,list里每个item是dict,内容是 'id':'abc' 这样 +# scada_model type 是类似pressure,flow之类的,是由Device 决定 的 +def get_all_scada_elements(name: str) -> list[dict[str, Any]]: + return read_all(name, 'select * from scada_element order by id') diff --git a/app/native/wndb/s32_region.py b/app/native/wndb/s32_region.py new file mode 100644 index 0000000..95fd67f --- /dev/null +++ b/app/native/wndb/s32_region.py @@ -0,0 +1,95 @@ +from .database import * +from .s32_region_util import from_postgis_polygon, to_postgis_polygon + +def get_region_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'boundary' : {'type': 'tuple_list' , 'optional': False , 'readonly': False} } + + +def get_region(name: str, id: str) -> dict[str, Any]: + r = try_read(name, f"select id, st_astext(boundary) as boundary_geom from region where id = '{id}'") + if r == None: + return {} + d = {} + d['id'] = str(r['id']) + d['boundary'] = from_postgis_polygon(str(r['boundary_geom'])) + return d + + +def _set_region(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + new = cs.operations[0]['boundary'] + old = get_region(name, id)['boundary'] + + redo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(new)}') where id = '{id}';" + undo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(old)}') where id = '{id}';" + redo_cs = g_update_prefix | { 'type': 'region', 'id': id, 'boundary': new } + undo_cs = g_update_prefix | { 'type': 'region', 'id': id, 'boundary': old } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_region(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0] or 'boundary' not in cs.operations[0]: + return ChangeSet() + b = cs.operations[0]['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + if get_region(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_region(name, cs)) + + +def _add_region(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + new = cs.operations[0]['boundary'] + + redo_sql = f"insert into region (id, boundary) values ('{id}', '{to_postgis_polygon(new)}');" + undo_sql = f"delete from region where id = '{id}';" + redo_cs = g_add_prefix | { 'type': 'region', 'id': id, 'boundary': new } + undo_cs = g_delete_prefix | { 'type': 'region', 'id': id } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_region(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0] or 'boundary' not in cs.operations[0]: + return ChangeSet() + b = cs.operations[0]['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + if get_region(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_region(name, cs)) + + +def _delete_region(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + old = get_region(name, id)['boundary'] + + redo_sql = f"delete from region where id = '{id}';" + undo_sql = f"insert into region (id, boundary) values ('{id}', '{to_postgis_polygon(old)}');" + redo_cs = g_delete_prefix | { 'type': 'region', 'id': id } + undo_cs = g_add_prefix | { 'type': 'region', 'id': id, 'boundary': old } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_region(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_region(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_region(name, cs)) + +def inp_in_region(line: str) -> str: + tokens = line.split() + return str(f"insert into _region (id, type) values ('{tokens[0]}', '{tokens[1]}');") + +def inp_in_bound(line: str) -> str: + tokens = line.split() + return tokens[0] + +def inp_in_regionnodes(line: str)->str: + tokens = line.split() + return tokens[0] \ No newline at end of file diff --git a/app/native/wndb/s32_region_util.py b/app/native/wndb/s32_region_util.py new file mode 100644 index 0000000..4fdb46d --- /dev/null +++ b/app/native/wndb/s32_region_util.py @@ -0,0 +1,463 @@ +import ctypes +import platform +import os +import math +from typing import Any +from .s0_base import get_node_links, get_link_nodes, is_pipe +from .s5_pipes import get_pipe +from .database import read, try_read, read_all, write +from .s24_coordinates import node_has_coord, get_node_coord + + +def from_postgis_polygon(polygon: str) -> list[tuple[float, float]]: + boundary = polygon.lower().removeprefix('polygon((').removesuffix('))').split(',') + xys = [] + for pt in boundary: + xy = pt.split(' ') + xys.append((float(xy[0]), float(xy[1]))) + return xys + + +def to_postgis_polygon(boundary: list[tuple[float, float]]) -> str: + polygon = '' + for pt in boundary: + polygon += f'{pt[0]} {pt[1]},' + return str(f'polygon(({polygon[:-1]}))') + + +def to_postgis_linestring(boundary: list[tuple[float, float]]) -> str: + line = '' + for pt in boundary: + line += f'{pt[0]} {pt[1]},' + return str(f'linestring({line[:-1]})') + + +def get_nodes_in_boundary(name: str, boundary: list[tuple[float, float]]) -> list[str]: + api = 'get_nodes_in_boundary' + write(name, f"delete from temp_region where id = '{api}'") + write(name, f"insert into temp_region (id, boundary) values ('{api}', '{to_postgis_polygon(boundary)}')") + + nodes: list[str] = [] + for row in read_all(name, f"select c.node from coordinates as c, temp_region as r where ST_Intersects(c.coord, r.boundary) and r.id = '{api}'"): + nodes.append(row['node']) + + write(name, f"delete from temp_region where id = '{api}'") + + return nodes + + +def _get_links_on_boundary(name: str, nodes: list[str]) -> list[str]: + links: list[str] = [] + + for node in nodes: + node_links = get_node_links(name, node) + for link in node_links: + if link in links: + continue + + link_nodes = get_link_nodes(name, link) + if link_nodes[0] in nodes and link_nodes[1] not in nodes: + links.append(link) + elif link_nodes[0] not in nodes and link_nodes[1] in nodes: + links.append(link) + + return links + + +# if region is general or wda => get_nodes_in_boundary +# if region is dma, sa or vd => get stored nodes in table +def get_nodes_in_region(name: str, region_id: str) -> list[str]: + nodes: list[str] = [] + + row = try_read(name, f"select r_type from region where id = '{region_id}'") + if row == None: + return nodes + + r_type = str(row['r_type']) + + if r_type == 'DMA' or r_type == 'SA' or r_type == 'VD': + table = '' + if r_type == 'DMA': + table = 'region_dma' + elif r_type == 'SA': + table = 'region_sa' + elif r_type == 'VD': + table = 'region_vd' + + if table != '': + row = try_read(name, f"select nodes from {table} where id = '{region_id}'") + if row != None: + nodes = eval(str(row['nodes'])) + + if nodes == []: + for row in read_all(name, f"select c.node from coordinates as c, region as r where ST_Intersects(c.coord, r.boundary) and r.id = '{region_id}'"): + nodes.append(row['node']) + + return nodes + + +def get_links_on_region_boundary(name: str, region_id: str) -> list[str]: + nodes = get_nodes_in_region(name, region_id) + print(nodes) + return _get_links_on_boundary(name, nodes) + + +def calculate_convex_hull(name: str, nodes: list[str]) -> list[tuple[float, float]]: + write(name, f'delete from temp_node') + for node in nodes: + write(name, f"insert into temp_node values ('{node}')") + + # TODO: check none + polygon = read(name, f'select st_astext(st_convexhull(st_collect(array(select coord from coordinates where node in (select * from temp_node))))) as boundary' )['boundary'] + write(name, f'delete from temp_node') + + return from_postgis_polygon(polygon) + + +def _verify_platform(): + _platform = platform.system() + if _platform != "Windows": + raise Exception(f'Platform {_platform} unsupported (not yet)') + + +def _normal(v: tuple[float, float]) -> tuple[float, float]: + l = math.sqrt(v[0] * v[0] + v[1] * v[1]) + return (v[0] / l, v[1] / l) + + +def _angle(v: tuple[float, float]) -> float: + if v[0] >= 0 and v[1] >= 0: + return math.asin(v[1]) + elif v[0] <= 0 and v[1] >= 0: + return math.pi - math.asin(v[1]) + elif v[0] <= 0 and v[1] <= 0: + return math.asin(-v[1]) + math.pi + elif v[0] >= 0 and v[1] <= 0: + return math.pi * 2 - math.asin(-v[1]) + return 0 + + +def _angle_of_node_link(node: str, link: str, nodes, links) -> float: + n1 = node + n2 = links[link]['node1'] if n1 == links[link]['node2'] else links[link]['node2'] + x1, y1 = nodes[n1]['x'], nodes[n1]['y'] + x2, y2 = nodes[n2]['x'], nodes[n2]['y'] + if y1 == y2: + v = ((x2 - x1) / abs(x2 - x1), 0.0) + else: + v = _normal((x2 - x1, y2 - y1)) + return _angle(v) + + +class Topology: + def __init__(self, db: str, nodes: list[str]) -> None: + self._nodes: dict[str, Any] = {} + self._max_x_node = '' + self._node_list: list[str] = [] + for node in nodes: + if not node_has_coord(db, node): + continue + if get_node_links(db, node) == 0: + continue + self._nodes[node] = get_node_coord(db, node) | { 'links': [] } + self._node_list.append(node) + if self._max_x_node == '' or self._nodes[node]['x'] > self._nodes[self._max_x_node]['x']: + self._max_x_node = node + + self._links: dict[str, Any] = {} + self._link_list: list[str] = [] + for node in self._nodes: + for link in get_node_links(db, node): + candidate = True + link_nodes = get_link_nodes(db, link) + for link_node in link_nodes: + if link_node not in self._nodes: + candidate = False + break + if candidate: + length = get_pipe(db, link)['length'] if is_pipe(db, link) else 0.0 + self._links[link] = { 'node1' : link_nodes[0], 'node2' : link_nodes[1], 'length' : length } + self._link_list.append(link) + if link not in self._nodes[link_nodes[0]]['links']: + self._nodes[link_nodes[0]]['links'].append(link) + if link not in self._nodes[link_nodes[1]]['links']: + self._nodes[link_nodes[1]]['links'].append(link) + + def nodes(self): + return self._nodes + + def node_list(self): + return self._node_list + + def max_x_node(self): + return self._max_x_node + + def links(self): + return self._links + + def link_list(self): + return self._link_list + + +def _calculate_boundary(cursor: str, t_nodes: dict[str, Any], t_links: dict[str, Any]) -> tuple[list[str], dict[str, list[str]], list[tuple[float, float]]]: + in_angle = 0 + + vertices: list[str] = [] + path: dict[str, list[str]] = {} + while True: + # prevent duplicated node + if len(vertices) > 0 and cursor == vertices[-1]: + break + + # prevent duplicated path + if len(vertices) >= 3 and vertices[0] == vertices[-1] and vertices[1] == cursor: + break + + vertices.append(cursor) + + sorted_links = [] + overlapped_link = '' + for link in t_nodes[cursor]['links']: + angle = _angle_of_node_link(cursor, link, t_nodes, t_links) + if angle == in_angle: + overlapped_link = link + continue + sorted_links.append((angle, link)) + + # work into a branch, return + if len(sorted_links) == 0: + path[overlapped_link] = [] + cursor = vertices[-2] + in_angle = _angle_of_node_link(cursor, overlapped_link, t_nodes, t_links) + continue + + sorted_links = sorted(sorted_links, key=lambda s:s[0]) + out_link = sorted_links[0][1] + for angle, link in sorted_links: + if angle > in_angle: + out_link = link + break + + path[out_link] = [] + cursor = t_links[out_link]['node1'] if cursor == t_links[out_link]['node2'] else t_links[out_link]['node2'] + in_angle = _angle_of_node_link(cursor, out_link, t_nodes, t_links) + + boundary: list[tuple[float, float]] = [] + for node in vertices: + boundary.append((t_nodes[node]['x'], t_nodes[node]['y'])) + + return (vertices, path, boundary) + + +def _collect_new_links(in_links: dict[str, list[str]], t_nodes: dict[str, Any], t_links: dict[str, Any], new_nodes: dict[str, Any], new_links: dict[str, Any]) -> tuple[dict[str, Any], dict[str, Any]]: + for link, pts in in_links.items(): + node1 = t_links[link]['node1'] + node2 = t_links[link]['node2'] + x1, x2 = t_nodes[node1]['x'], t_nodes[node2]['x'] + y1, y2 = t_nodes[node1]['y'], t_nodes[node2]['y'] + + if node1 not in new_nodes: + new_nodes[node1] = { 'x': x1, 'y': y1, 'links': [] } + if node2 not in new_nodes: + new_nodes[node2] = { 'x': x2, 'y': y2, 'links': [] } + + x_delta = x2 - x1 + y_delta = y2 - y1 + use_x = abs(x_delta) > abs(y_delta) + + if len(pts) == 0: + new_links[link] = t_links[link] + else: + sorted_nodes: list[tuple[float, str]] = [] + sorted_nodes.append((0.0, node1)) + sorted_nodes.append((1.0, node2)) + i = 0 + for pt in pts: + x, y = new_nodes[pt]['x'], new_nodes[pt]['y'] + percent = ((x - x1) / x_delta) if use_x else ((y - y1) / y_delta) + sorted_nodes.append((percent, pt)) + i += 1 + sorted_nodes = sorted(sorted_nodes, key=lambda s:s[0]) + + for i in range(1, len(sorted_nodes)): + l = sorted_nodes[i - 1][1] + r = sorted_nodes[i][1] + new_link = f'LINK_[{l}]_[{r}]' + new_links[new_link] = { 'node1': l, 'node2': r } + + return (new_nodes, new_links) + + +def calculate_boundary(name: str, nodes: list[str], accurate = False) -> list[tuple[float, float]]: + topology = Topology(name, nodes) + t_nodes = topology.nodes() + t_links = topology.links() + + vertices, path, boundary = _calculate_boundary(topology.max_x_node(), t_nodes, t_links) + + if not accurate: + return boundary + + api = 'calculate_boundary' + write(name, f"delete from temp_region where id = '{api}'") + # use linestring instead of polygon to reduce strict limitation + # TODO: linestring can not work well + write(name, f"insert into temp_region (id, boundary) values ('{api}', '{to_postgis_polygon(boundary)}')") + + write(name, f'delete from temp_node') + for node in nodes: + write(name, f"insert into temp_node values ('{node}')") + + for row in read_all(name, f"select n.node from coordinates as c, temp_node as n, temp_region as r where c.node = n.node and ST_Intersects(c.coord, r.boundary) and r.id = '{api}'"): + node = row['node'] + write(name, f"delete from temp_node where node = '{node}'") + + outside_nodes: list[str] = [] + for row in read_all(name, "select node from temp_node"): + outside_nodes.append(row['node']) + + # no outside nodes, return + if len(outside_nodes) == 0: + write(name, f'delete from temp_node') + write(name, f"delete from temp_region where id = '{api}'") + return boundary + + new_nodes: dict[str, Any] = {} + new_links: dict[str, Any] = {} + + boundary_links: dict[str, list[str]] = {} + write(name, "delete from temp_link_2") + for node in outside_nodes: + for link in t_nodes[node]['links']: + node1 = t_links[link]['node1'] + node2 = t_links[link]['node2'] + if node1 in outside_nodes and node2 not in outside_nodes and node2 not in vertices and link: + if link not in boundary: + boundary_links[link] = [] + line = f"LINESTRING({t_nodes[node1]['x']} {t_nodes[node1]['y']}, {t_nodes[node2]['x']} {t_nodes[node2]['y']})" + write(name, f"insert into temp_link_2 values ('{link}', '{line}')") + if node2 in outside_nodes and node1 not in outside_nodes and node1 not in vertices: + if link not in boundary: + boundary_links[link] = [] + line = f"LINESTRING({t_nodes[node1]['x']} {t_nodes[node1]['y']}, {t_nodes[node2]['x']} {t_nodes[node2]['y']})" + write(name, f"insert into temp_link_2 values ('{link}', '{line}')") + if node1 in outside_nodes and node2 in outside_nodes: + x1, x2 = t_nodes[node1]['x'], t_nodes[node2]['x'] + y1, y2 = t_nodes[node1]['y'], t_nodes[node2]['y'] + if node1 not in new_nodes: + new_nodes[node1] = { 'x': x1, 'y': y1, 'links': [] } + if node2 not in new_nodes: + new_nodes[node2] = { 'x': x2, 'y': y2, 'links': [] } + if link not in new_links: + new_links[link] = t_links[link] + + # no boundary links, return + if len(boundary_links) == 0: + write(name, "delete from temp_link_2") + write(name, f'delete from temp_node') + write(name, f"delete from temp_region where id = '{api}'") + return boundary + + write(name, "delete from temp_link_1") + for link, _ in path.items(): + node1 = t_links[link]['node1'] + node2 = t_links[link]['node2'] + line = f"LINESTRING({t_nodes[node1]['x']} {t_nodes[node1]['y']}, {t_nodes[node2]['x']} {t_nodes[node2]['y']})" + write(name, f"insert into temp_link_1 (link, geom) values ('{link}', '{line}')") + + has_intersection = False + for row in read_all(name, f"select l1.link as l, l2.link as r, st_astext(st_intersection(l1.geom, l2.geom)) as p from temp_link_1 as l1, temp_link_2 as l2 where st_intersects(l1.geom, l2.geom)"): + has_intersection = True + + link1, link2, pt = str(row['l']), str(row['r']), str(row['p']) + pts = pt.lower().removeprefix('point(').removesuffix(')').split(' ') + xy = (float(pts[0]), float(pts[1])) + + new_node = f'NODE_[{link1}]_[{link2}]' + new_nodes[new_node] = { 'x': xy[0], 'y': xy[1], 'links': [] } + + path[link1].append(new_node) + boundary_links[link2].append(new_node) + + # no intersection, return + if not has_intersection: + write(name, "delete from temp_link_1") + write(name, "delete from temp_link_2") + write(name, 'delete from temp_node') + write(name, f"delete from temp_region where id = '{api}'") + return boundary + + new_nodes, new_links = _collect_new_links(path, t_nodes, t_links, new_nodes, new_links) + new_nodes, new_links = _collect_new_links(boundary_links, t_nodes, t_links, new_nodes, new_links) + + for link, values in new_links.items(): + new_nodes[values['node1']]['links'].append(link) + new_nodes[values['node2']]['links'].append(link) + + _, _, boundary = _calculate_boundary(topology.max_x_node(), new_nodes, new_links) + + write(name, "delete from temp_link_1") + write(name, "delete from temp_link_2") + write(name, 'delete from temp_node') + write(name, f"delete from temp_region where id = '{api}'") + + return boundary + + +''' +# CClipper2.dll +# int inflate_paths(double* path, size_t size, double delta, int jt, int et, double miter_limit, int precision, double arc_tolerance, double** out_path, size_t* out_size); +# int simplify_paths(double* path, size_t size, double epsilon, int is_closed_path, double** out_path, size_t* out_size); +# void free_paths(double** paths); +''' +def inflate_boundary(name: str, boundary: list[tuple[float, float]], delta: float = 0.5) -> list[tuple[float, float]]: + if boundary[0] == boundary[-1]: + del(boundary[-1]) + + lib = ctypes.CDLL(os.path.join(os.getcwd(), 'api', 'CClipper2.dll')) + + c_size = ctypes.c_size_t(len(boundary) * 2) + c_path = (ctypes.c_double * c_size.value)() + i = 0 + for xy in boundary: + c_path[i] = xy[0] + i += 1 + c_path[i] = xy[1] + i += 1 + c_delta = ctypes.c_double(delta) + JoinType_Square, JoinType_Round, JoinType_Miter = 0, 1, 2 + c_jt = ctypes.c_int(JoinType_Square) + EndType_Polygon, EndType_Joined, EndType_Butt, EndType_Square, EndType_Round = 0, 1, 2, 3, 4 + c_et = ctypes.c_int(EndType_Polygon) + c_miter_limit = ctypes.c_double(2.0) + c_precision = ctypes.c_int(2) + c_arc_tolerance = ctypes.c_double(0.0) + c_out_path = ctypes.POINTER(ctypes.c_double)() + c_out_size = ctypes.c_size_t(0) + + lib.inflate_paths(c_path, c_size, c_delta, c_jt, c_et, c_miter_limit, c_precision, c_arc_tolerance, ctypes.byref(c_out_path), ctypes.byref(c_out_size)) + if c_out_size.value == 0: + lib.free_paths(ctypes.byref(c_out_path)) + return [] + + # TODO: simplify_paths :) + + result: list[tuple[float, float]] = [] + for i in range(0, c_out_size.value, 2): + result.append((c_out_path[i], c_out_path[i + 1])) + result.append(result[0]) + + lib.free_paths(ctypes.byref(c_out_path)) + return result + + +def inflate_region(name: str, region_id: str, delta: float = 0.5) -> list[tuple[float, float]]: + r = try_read(name, f"select id, st_astext(boundary) as boundary_geom from region where id = '{region_id}'") + if r == None: + return [] + boundary = from_postgis_polygon(str(r['boundary_geom'])) + return inflate_boundary(name, boundary, delta) + + +if __name__ == '__main__': + _verify_platform() diff --git a/app/native/wndb/s33_dma.py b/app/native/wndb/s33_dma.py new file mode 100644 index 0000000..49198c9 --- /dev/null +++ b/app/native/wndb/s33_dma.py @@ -0,0 +1,230 @@ +from .database import * +from .s0_base import is_node +from .s32_region_util import to_postgis_polygon +from .s32_region import get_region + +def get_district_metering_area_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'boundary' : {'type': 'tuple_list' , 'optional': False , 'readonly': False }, + 'parent' : {'type': 'str' , 'optional': True , 'readonly': False }, + 'level' : {'type': 'int' , 'optional': False , 'readonly': True } } + + +def get_district_metering_area(name: str, id: str) -> dict[str, Any]: + dma = get_region(name, id) + if dma == {}: + return {} + r = try_read(name, f"select * from region_dma where id = '{id}'") + if r == None: + return {} + dma['parent'] = r['parent'] + dma['nodes'] = list(eval(r['nodes'])) + dma['level'] = 1 + + if dma['parent'] != None: + parent = dma['parent'] + while parent != None: + parent = read(name, f"select parent from region_dma where id = '{parent}'")['parent'] + dma['level'] += 1 + + return dma + + +def _set_district_metering_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + new_boundary = cs.operations[0]['boundary'] + old_boundary = get_region(name, id)['boundary'] + + new_parent = cs.operations[0]['parent'] + f_new_parent = f"'{new_parent}'" if new_parent != None else 'null' + + new_nodes = cs.operations[0]['nodes'] + str_new_nodes = str(new_nodes).replace("'", "''") + + old = get_district_metering_area(name, id) + old_parent = old['parent'] + f_old_parent = f"'{old_parent}'" if old_parent != None else 'null' + + old_nodes = old['nodes'] + str_old_nodes = str(old_nodes).replace("'", "''") + + redo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(new_boundary)}') where id = '{id}';" + redo_sql += f"update region_dma set parent = {f_new_parent}, nodes = '{str_new_nodes}' where id = '{id}';" + + undo_sql = f"update region_dma set parent = {f_old_parent}, nodes = '{str_old_nodes}' where id = '{id}';" + undo_sql += f"update region set boundary = st_geomfromtext('{to_postgis_polygon(old_boundary)}') where id = '{id}';" + + redo_cs = g_update_prefix | { 'type': 'district_metering_area', 'id': id, 'boundary': new_boundary, 'parent': new_parent, 'nodes': new_nodes } + undo_cs = g_update_prefix | { 'type': 'district_metering_area', 'id': id, 'boundary': old_boundary, 'parent': old_parent, 'nodes': old_nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_district_metering_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + dma = get_district_metering_area(name, op['id']) + if dma == {}: + return ChangeSet() + + if 'boundary' not in op: + op['boundary'] = dma['boundary'] + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'parent' not in op: + op['parent'] = dma['parent'] + + if op['parent'] != None and get_district_metering_area(name, op['parent']) == {}: + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = dma['nodes'] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _set_district_metering_area(name, cs)) + + +def _add_district_metering_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + boundary = cs.operations[0]['boundary'] + + parent = cs.operations[0]['parent'] + f_parent = f"'{parent}'" if parent != None else 'null' + + nodes = cs.operations[0]['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'DMA');" + redo_sql += f"insert into region_dma (id, parent, nodes) values ('{id}', {f_parent}, '{str_nodes}');" + + undo_sql = f"delete from region_dma where id = '{id}';" + undo_sql += f"delete from region where id = '{id}';" + + redo_cs = g_add_prefix | { 'type': 'district_metering_area', 'id': id, 'boundary': boundary, 'parent': parent, 'nodes': nodes } + undo_cs = g_delete_prefix | { 'type': 'district_metering_area', 'id': id } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_district_metering_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + dma = get_district_metering_area(name, op['id']) + if dma != {}: + return ChangeSet() + + if 'boundary' not in op: + return ChangeSet() + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'parent' not in op: + op['parent'] = None + + if op['parent'] != None and get_district_metering_area(name, op['parent']) == {}: + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = [] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _add_district_metering_area(name, cs)) + + +def _delete_district_metering_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + dma = get_district_metering_area(name, id) + boundary = dma['boundary'] + parent = dma['parent'] + f_parent = f"'{parent}'" if parent != None else 'null' + nodes = dma['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"delete from region_dma where id = '{id}';" + redo_sql += f"delete from region where id = '{id}';" + + undo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'DMA');" + undo_sql += f"insert into region_dma (id, parent, nodes) values ('{id}', {f_parent}, '{str_nodes}');" + + redo_cs = g_delete_prefix | { 'type': 'district_metering_area', 'id': id } + undo_cs = g_add_prefix | { 'type': 'district_metering_area', 'id': id, 'boundary': boundary, 'parent': parent, 'nodes': nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def _has_child(name: str, parent: str) -> bool: + return try_read(name, f"select * from region_dma where parent = '{parent}'") != None + + +def is_descendant_of(name: str, descendant: str, ancestor: str) -> bool: + parent = descendant + while parent != None: + parent = read(name, f"select parent from region_dma where id = '{parent}'")['parent'] + if parent == ancestor: + return True + return False + + +def delete_district_metering_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + dma = get_district_metering_area(name, op['id']) + if dma == {}: + return ChangeSet() + + #TODO: cascade ? + if _has_child(name, dma['id']): + return ChangeSet() + + return execute_command(name, _delete_district_metering_area(name, cs)) + + +def get_all_district_metering_area_ids(name: str) -> list[str]: + ids = [] + for row in read_all(name, f"select id from region_dma"): + ids.append(row['id']) + return ids + + +def get_all_district_metering_areas(name: str) -> list[dict[str, Any]]: + result = [] + for id in get_all_district_metering_area_ids(name): + result.append(get_district_metering_area(name, id)) + return result diff --git a/app/native/wndb/s33_dma_cal.py b/app/native/wndb/s33_dma_cal.py new file mode 100644 index 0000000..e2d7ae9 --- /dev/null +++ b/app/native/wndb/s33_dma_cal.py @@ -0,0 +1,152 @@ +import ctypes +import os +import numpy as np +import pymetis +from .database import * +from .s0_base import get_nodes +from .s32_region_util import get_nodes_in_region +from .s32_region_util import Topology + + +PARTITION_TYPE_RB = 0 +PARTITION_TYPE_KWAY = 1 + +''' +adjacency_list = [np.array([4, 2, 1]), + np.array([0, 2, 3]), + np.array([4, 3, 1, 0]), + np.array([1, 2, 5, 6]), + np.array([0, 2, 5]), + np.array([4, 3, 6]), + np.array([5, 3])] +n_cuts, membership = pymetis.part_graph(2, adjacency=adjacency_list) +# n_cuts = 3 +# membership = [1, 1, 1, 0, 1, 0, 0] + +nodes_part_0 = np.argwhere(np.array(membership) == 0).ravel() # [3, 5, 6] +nodes_part_1 = np.argwhere(np.array(membership) == 1).ravel() # [0, 1, 2, 4] + +print(nodes_part_0) +print(nodes_part_1) +''' + + +def calculate_district_metering_area_for_nodes(name: str, nodes: list[str], part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: + topology = Topology(name, nodes) + t_nodes = topology.nodes() + t_links = topology.links() + t_node_list = topology.node_list() + + adjacency_list = [] + + for node in t_node_list: + links: list[str] = t_nodes[node]['links'] + a_nodes: list[int] = [] + for link in links: + if t_links[link]['node1'] == node: + i = t_node_list.index(t_links[link]['node2']) + a_nodes.append(i) + elif t_links[link]['node2'] == node: + i = t_node_list.index(t_links[link]['node1']) + a_nodes.append(i) + adjacency_list.append(np.array(a_nodes)) + + recursive = part_type == PARTITION_TYPE_RB + n_cuts, membership = pymetis.part_graph(nparts=part_count, adjacency=adjacency_list, recursive=recursive, contiguous=True) + + result: list[list[str]] = [] + for i in range(0, part_count): + indices: list[int] = list(np.argwhere(np.array(membership) == i).ravel()) + index_strs: list[str] = [] + for index in indices: + index_strs.append(t_node_list[index]) + result.append(index_strs) + + return result + + +def _calculate_district_metering_area_for_nodes(name: str, nodes: list[str], part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: + if part_type != PARTITION_TYPE_RB and part_type != PARTITION_TYPE_KWAY: + return [] + if part_count <= 0: + return [] + elif part_count == 1: + return [nodes] + + lib = ctypes.CDLL(os.path.join(os.getcwd(), 'api', 'CMetis.dll')) + + METIS_NOPTIONS = 40 + c_options = (ctypes.c_int64 * METIS_NOPTIONS)() + + METIS_OK = 1 + result = lib.set_default_options(c_options) + if result != METIS_OK: + return [] + + METIS_OPTION_PTYPE , METIS_OPTION_CONTIG = 0, 13 + c_options[METIS_OPTION_PTYPE] = part_type + c_options[METIS_OPTION_CONTIG] = 1 + + topology = Topology(name, nodes) + t_nodes = topology.nodes() + t_links = topology.links() + t_node_list = topology.node_list() + t_link_list = topology.link_list() + + nedges = len(t_link_list) * 2 + + c_nvtxs = ctypes.c_int64(len(t_node_list)) + c_ncon = ctypes.c_int64(1) + c_xadj = (ctypes.c_int64 * (c_nvtxs.value + 1))() + c_adjncy = (ctypes.c_int64 * nedges)() + c_vwgt = (ctypes.c_int64 * (c_ncon.value * c_nvtxs.value))() + c_adjwgt = (ctypes.c_int64 * nedges)() + c_vsize = (ctypes.c_int64 * c_nvtxs.value)() + + c_xadj[0] = 0 + + l, n = 0, 0 + c_xadj_i = 1 + for node in t_node_list: + links = t_nodes[node]['links'] + for link in links: + node1 = t_links[link]['node1'] + node2 = t_links[link]['node2'] + c_adjncy[l] = t_node_list.index(node2) if node2 != node else t_node_list.index(node1) + c_adjwgt[l] = 1 + l += 1 + if len(links) > 0: + c_xadj[c_xadj_i] = l # adjncy.size() + c_xadj_i += 1 + c_vwgt[n] = 1 + c_vsize[n] = 1 + n += 1 + + part_func = lib.part_graph_recursive if part_type == PARTITION_TYPE_RB else lib.part_graph_kway + + c_nparts = ctypes.c_int64(part_count) + c_tpwgts = ctypes.POINTER(ctypes.c_double)() + c_ubvec = ctypes.POINTER(ctypes.c_double)() + c_out_edgecut = ctypes.c_int64(0) + c_out_part = (ctypes.c_int64 * c_nvtxs.value)() + result = part_func(ctypes.byref(c_nvtxs), ctypes.byref(c_ncon), c_xadj, c_adjncy, c_vwgt, c_vsize, c_adjwgt, ctypes.byref(c_nparts), c_tpwgts, c_ubvec, c_options, ctypes.byref(c_out_edgecut), c_out_part) + if result != METIS_OK: + return [] + + dmas : list[list[str]]= [] + for i in range(part_count): + dmas.append([]) + for i in range(c_nvtxs.value): + dmas[c_out_part[i]].append(t_node_list[i]) + + return dmas + + +def calculate_district_metering_area_for_region(name: str, region: str, part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: + nodes = get_nodes_in_region(name, region) + return calculate_district_metering_area_for_nodes(name, nodes, part_count, part_type) + + +def calculate_district_metering_area_for_network(name: str, part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]: + nodes = get_nodes(name) + return calculate_district_metering_area_for_nodes(name, nodes, part_count, part_type) diff --git a/app/native/wndb/s33_dma_gen.py b/app/native/wndb/s33_dma_gen.py new file mode 100644 index 0000000..4a88fdc --- /dev/null +++ b/app/native/wndb/s33_dma_gen.py @@ -0,0 +1,47 @@ +from .s32_region_util import calculate_boundary, inflate_boundary +from .s33_dma_cal import * +from .s33_dma import get_all_district_metering_area_ids, get_all_district_metering_areas, get_district_metering_area, is_descendant_of +from .batch_exe import execute_batch_command + + +def generate_district_metering_area(name: str, part_count: int = 1, part_type: int = PARTITION_TYPE_RB, inflate_delta: float = 0.5) -> ChangeSet: + cs = ChangeSet() + + dmas = get_all_district_metering_areas(name) + max_level = 0 + for dma in dmas: + if dma['level'] > max_level: + max_level = dma['level'] + while max_level > 0: + for dma in dmas: + if dma['level'] == max_level: + cs.delete({ 'type': 'district_metering_area', 'id': dma['id'] }) + max_level -= 1 + + i = 1 + for nodes in calculate_district_metering_area_for_network(name, part_count, part_type): + boundary = calculate_boundary(name, nodes) + boundary = inflate_boundary(name, boundary, inflate_delta) + cs.add({ 'type': 'district_metering_area', 'id': f"DMA_1_{i}", 'boundary': boundary, 'parent': None, 'nodes': nodes }) + i += 1 + + return execute_batch_command(name, cs) + + +def generate_sub_district_metering_area(name: str, dma: str, part_count: int = 1, part_type: int = PARTITION_TYPE_RB, inflate_delta: float = 0.5) -> ChangeSet: + cs = ChangeSet() + + for id in get_all_district_metering_area_ids(name): + if is_descendant_of(name, id, dma): + cs.delete({ 'type': 'district_metering_area', 'id': id }) + + level = get_district_metering_area(name, dma)['level'] + 1 + + i = 1 + for nodes in calculate_district_metering_area_for_region(name, dma, part_count, part_type): + boundary = calculate_boundary(name, nodes) + boundary = inflate_boundary(name, boundary, inflate_delta) + cs.add({ 'type': 'district_metering_area', 'id': f"DMA_[{dma}]_{level}_{i}", 'boundary': boundary, 'parent': dma, 'nodes': nodes }) + i += 1 + + return execute_batch_command(name, cs) diff --git a/app/native/wndb/s34_sa.py b/app/native/wndb/s34_sa.py new file mode 100644 index 0000000..ec54c2c --- /dev/null +++ b/app/native/wndb/s34_sa.py @@ -0,0 +1,217 @@ +from .database import * +from .s0_base import is_node +from .s32_region_util import to_postgis_polygon +from .s32_region import get_region + +def get_service_area_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'boundary' : {'type': 'tuple_list' , 'optional': False , 'readonly': False }, + 'source' : {'type': 'str' , 'optional': False , 'readonly': False }, + 'time_index' : {'type': 'int' , 'optional': False , 'readonly': False } } + +def get_service_area(name: str, id: str) -> dict[str, Any]: + sa = get_region(name, id) + if sa == {}: + return {} + r = try_read(name, f"select * from region_sa where id = '{id}'") + if r == None: + return {} + sa['source'] = r['source'] + sa['nodes'] = list(eval(r['nodes'])) + sa['time_index'] = r['time_index'] + return sa + +def _set_service_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + new_boundary = cs.operations[0]['boundary'] + old_boundary = get_region(name, id)['boundary'] + + new_source = cs.operations[0]['source'] + f_new_source = f"'{new_source}'" + + new_nodes = cs.operations[0]['nodes'] + str_new_nodes = str(new_nodes).replace("'", "''") + + new_time_index = cs.operations[0]['time_index'] + + old = get_service_area(name, id) + old_source = old['source'] + f_old_source = f"'{old_source}'" + + old_nodes = old['nodes'] + str_old_nodes = str(old_nodes).replace("'", "''") + + old_time_index = old['time_index'] + + redo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(new_boundary)}') where id = '{id}';" + redo_sql += f"update region_sa set time_index = {new_time_index}, source = {f_new_source}, nodes = '{str_new_nodes}' where id = '{id}';" + + undo_sql = f"update region_sa set time_index = {old_time_index}, source = {f_old_source}, nodes = '{str_old_nodes}' where id = '{id}';" + undo_sql += f"update region set boundary = st_geomfromtext('{to_postgis_polygon(old_boundary)}') where id = '{id}';" + + redo_cs = g_update_prefix | { 'type': 'service_area', 'id': id, 'boundary': new_boundary, 'time_index': new_time_index, 'source': new_source, 'nodes': new_nodes } + undo_cs = g_update_prefix | { 'type': 'service_area', 'id': id, 'boundary': old_boundary, 'time_index': old_time_index, 'source': old_source, 'nodes': old_nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_service_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + sa = get_service_area(name, op['id']) + if sa == {}: + return ChangeSet() + + if 'boundary' not in op: + op['boundary'] = sa['boundary'] + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'time_index' not in op: + op['time_index'] = sa['time_index'] + + if 'source' not in op: + op['source'] = sa['source'] + + if not is_node(name, op['source']): + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = sa['nodes'] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _set_service_area(name, cs)) + + +def _add_service_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + boundary = cs.operations[0]['boundary'] + + time_index = cs.operations[0]['time_index'] + + source = cs.operations[0]['source'] + f_source = f"'{source}'" + + nodes = cs.operations[0]['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'SA');" + redo_sql += f"insert into region_sa (id, time_index, source, nodes) values ('{id}', {time_index}, {f_source}, '{str_nodes}');" + + undo_sql = f"delete from region_sa where id = '{id}';" + undo_sql += f"delete from region where id = '{id}';" + + redo_cs = g_add_prefix | { 'type': 'service_area', 'id': id, 'boundary': boundary, 'time_index': time_index, 'source': source, 'nodes': nodes } + undo_cs = g_delete_prefix | { 'type': 'service_area', 'id': id } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_service_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + sa = get_service_area(name, op['id']) + if sa != {}: + return ChangeSet() + + if 'boundary' not in op: + return ChangeSet() + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'time_index' not in op: + return ChangeSet() + + if 'source' not in op: + return ChangeSet() + + if not is_node(name, op['source']): + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = [] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _add_service_area(name, cs)) + + +def _delete_service_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + sa = get_service_area(name, id) + boundary = sa['boundary'] + time_index = sa['time_index'] + source = sa['source'] + f_source = f"'{source}'" + nodes = sa['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"delete from region_sa where id = '{id}';" + redo_sql += f"delete from region where id = '{id}';" + + undo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'SA');" + undo_sql += f"insert into region_sa (id, time_index, source, nodes) values ('{id}', {time_index}, {f_source}, '{str_nodes}');" + + redo_cs = g_delete_prefix | { 'type': 'service_area', 'id': id } + undo_cs = g_add_prefix | { 'type': 'service_area', 'id': id, 'boundary': boundary, 'time_index': time_index, 'source': source, 'nodes': nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_service_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + sa = get_service_area(name, op['id']) + if sa == {}: + return ChangeSet() + + return execute_command(name, _delete_service_area(name, cs)) + + +def get_all_service_area_ids(name: str) -> list[str]: + ids = [] + for row in read_all(name, f"select id from region_sa"): + ids.append(row['id']) + return ids + + +def get_all_service_areas(name: str) -> list[dict[str, Any]]: + result = [] + for id in get_all_service_area_ids(name): + result.append(get_service_area(name, id)) + return result diff --git a/app/native/wndb/s34_sa_cal.py b/app/native/wndb/s34_sa_cal.py new file mode 100644 index 0000000..025b4c1 --- /dev/null +++ b/app/native/wndb/s34_sa_cal.py @@ -0,0 +1,198 @@ +import os +import ctypes +from .project import have_project +from .inp_out import dump_inp + +def calculate_service_area(name: str) -> list[dict[str, list[str]]]: + if not have_project(name): + raise Exception(f'Not found project [{name}]') + + dir = os.path.abspath(os.getcwd()) + + inp_str = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') + dump_inp(name, inp_str, '2') + + toolkit = ctypes.CDLL(os.path.join(os.path.join(dir, 'api'), 'toolkit.dll')) + + inp = ctypes.c_char_p(inp_str.encode()) + + handle = ctypes.c_ulonglong() + toolkit.TK_ServiceArea_Start(inp, ctypes.byref(handle)) + + c_nodeCount = ctypes.c_size_t() + toolkit.TK_ServiceArea_GetNodeCount(handle, ctypes.byref(c_nodeCount)) + nodeCount = c_nodeCount.value + + nodeIds: list[str] = [] + + for n in range(0, nodeCount): + id = ctypes.c_char_p() + toolkit.TK_ServiceArea_GetNodeId(handle, ctypes.c_size_t(n), ctypes.byref(id)) + nodeIds.append(id.value.decode()) + + c_timeCount = ctypes.c_size_t() + toolkit.TK_ServiceArea_GetTimeCount(handle, ctypes.byref(c_timeCount)) + timeCount = c_timeCount.value + + results: list[dict[str, list[str]]] = [] + + for t in range(0, timeCount): + c_sourceCount = ctypes.c_size_t() + toolkit.TK_ServiceArea_GetSourceCount(handle, ctypes.c_size_t(t), ctypes.byref(c_sourceCount)) + sourceCount = c_sourceCount.value + + sources = ctypes.POINTER(ctypes.c_size_t)() + toolkit.TK_ServiceArea_GetSources(handle, ctypes.c_size_t(t), ctypes.byref(sources)) + + result: dict[str, list[str]] = {} + for s in range(0, sourceCount): + result[nodeIds[sources[s]]] = [] + + for n in range(0, nodeCount): + concentration = ctypes.POINTER(ctypes.c_double)() + toolkit.TK_ServiceArea_GetConcentration(handle, ctypes.c_size_t(t), ctypes.c_size_t(n), ctypes.byref(concentration)) + + maxS = sources[0] + maxC = concentration[0] + for s in range(1, sourceCount): + if concentration[s] > maxC: + maxS = sources[s] + maxC = concentration[s] + + result[nodeIds[maxS]].append(nodeIds[n]) + + results.append(result) + + toolkit.TK_ServiceArea_End(handle) + + return results + +''' +import sys +import json +from queue import Queue +from .database import * +from .s0_base import get_node_links, get_link_nodes + +sys.path.append('..') +from app.infra.epanet.epanet import run_project + +def _calculate_service_area(name: str, inp, time_index: int = 0) -> dict[str, list[str]]: + sources : dict[str, list[str]] = {} + for node_result in inp['node_results']: + result = node_result['result'][time_index] + if result['demand'] < 0: + sources[node_result['node']] = [] + + link_flows: dict[str, float] = {} + for link_result in inp['link_results']: + result = link_result['result'][time_index] + link_flows[link_result['link']] = float(result['flow']) + + # build source to nodes map + for source in sources: + queue = Queue() + queue.put(source) + + while not queue.empty(): + cursor = queue.get() + if cursor not in sources[source]: + sources[source].append(cursor) + + links = get_node_links(name, cursor) + for link in links: + node1, node2 = get_link_nodes(name, link) + if node1 == cursor and link_flows[link] > 0: + queue.put(node2) + elif node2 == cursor and link_flows[link] < 0: + queue.put(node1) + + #return sources + + # calculation concentration + concentration_map: dict[str, dict[str, float]] = {} + node_wip: list[str] = [] + for source, nodes in sources.items(): + for node in nodes: + if node not in concentration_map: + concentration_map[node] = {} + concentration_map[node][source] = 0.0 + if node not in node_wip: + node_wip.append(node) + + # if only one source, done + for node, concentrations in concentration_map.items(): + if len(concentrations) == 1: + node_wip.remove(node) + for key in concentrations.keys(): + concentration_map[node][key] = 1.0 + + node_upstream : dict[str, list[tuple[str, str]]] = {} + for node in node_wip: + if node not in node_upstream: + node_upstream[node] = [] + + links = get_node_links(name, node) + for link in links: + node1, node2 = get_link_nodes(name, link) + if node2 == node and link_flows[link] > 0: + node_upstream[node].append((link, node1)) + elif node1 == node and link_flows[link] < 0: + node_upstream[node].append((link, node2)) + + while len(node_wip) != 0: + done = [] + for node in node_wip: + up_link_nodes = node_upstream[node] + ready = True + for link_node in up_link_nodes: + if link_node[1] in node_wip: + ready = False + break + if ready: + for link_node in up_link_nodes: + if link_node[1] not in concentration_map.keys(): + continue + for source, concentration in concentration_map[link_node[1]].items(): + concentration_map[node][source] += concentration * abs(link_flows[link_node[0]]) + + # normalize + sum = 0.0 + for source, concentration in concentration_map[node].items(): + sum += concentration + for source in concentration_map[node].keys(): + concentration_map[node][source] /= sum + + done.append(node) + + for node in done: + node_wip.remove(node) + + source_to_main_node: dict[str, list[str]] = {} + for node, value in concentration_map.items(): + max_source = '' + max_concentration = 0.0 + for s, c in value.items(): + if c > max_concentration: + max_concentration = c + max_source = s + if max_source not in source_to_main_node: + source_to_main_node[max_source] = [] + source_to_main_node[max_source].append(node) + + return source_to_main_node + + +def calculate_service_area(name: str) -> list[dict[str, list[str]]]: + inp = json.loads(run_project(name, True)) + + result: list[dict[str, list[str]]] = [] + + time_count = len(inp['node_results'][0]['result']) + + for i in range(time_count): + sas = _calculate_service_area(name, inp, i) + result.append(sas) + + return result +''' diff --git a/app/native/wndb/s34_sa_gen.py b/app/native/wndb/s34_sa_gen.py new file mode 100644 index 0000000..7eb7ff8 --- /dev/null +++ b/app/native/wndb/s34_sa_gen.py @@ -0,0 +1,23 @@ +from .s32_region_util import calculate_boundary, inflate_boundary +from .s34_sa_cal import * +from .s34_sa import get_all_service_area_ids +from .batch_exe import execute_batch_command +from .database import ChangeSet + +def generate_service_area(name: str, inflate_delta: float = 0.5) -> ChangeSet: + cs = ChangeSet() + + for id in get_all_service_area_ids(name): + cs.delete({'type': 'service_area', 'id': id}) + + sass = calculate_service_area(name) + + time_index = 0 + for sas in sass: + for source, nodes in sas.items(): + boundary = calculate_boundary(name, nodes) + boundary = inflate_boundary(name, boundary, inflate_delta) + cs.add({ 'type': 'service_area', 'id': f"SA_{source}_{time_index}", 'boundary': boundary, 'time_index': time_index, 'source': source, 'nodes': nodes }) + time_index += 1 + + return execute_batch_command(name, cs) diff --git a/app/native/wndb/s35_vd.py b/app/native/wndb/s35_vd.py new file mode 100644 index 0000000..feddd1d --- /dev/null +++ b/app/native/wndb/s35_vd.py @@ -0,0 +1,202 @@ +from .database import * +from .s0_base import is_node +from .s32_region_util import to_postgis_polygon +from .s32_region import get_region + +def get_virtual_district_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'boundary' : {'type': 'tuple_list' , 'optional': False , 'readonly': False }, + 'center' : {'type': 'str' , 'optional': False , 'readonly': False } } + +def get_virtual_district(name: str, id: str) -> dict[str, Any]: + vd = get_region(name, id) + if vd == {}: + return {} + r = try_read(name, f"select * from region_vd where id = '{id}'") + if r == None: + return {} + vd['center'] = r['center'] + vd['nodes'] = list(eval(r['nodes'])) + return vd + +def _set_virtual_district(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + new_boundary = cs.operations[0]['boundary'] + old_boundary = get_region(name, id)['boundary'] + + new_center = cs.operations[0]['center'] + f_new_center = f"'{new_center}'" + + new_nodes = cs.operations[0]['nodes'] + str_new_nodes = str(new_nodes).replace("'", "''") + + old = get_virtual_district(name, id) + old_center = old['center'] + f_old_center = f"'{old_center}'" + + old_nodes = old['nodes'] + str_old_nodes = str(old_nodes).replace("'", "''") + + redo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(new_boundary)}') where id = '{id}';" + redo_sql += f"update region_vd set center = {f_new_center}, nodes = '{str_new_nodes}' where id = '{id}';" + + undo_sql = f"update region_vd set center = {f_old_center}, nodes = '{str_old_nodes}' where id = '{id}';" + undo_sql += f"update region set boundary = st_geomfromtext('{to_postgis_polygon(old_boundary)}') where id = '{id}';" + + redo_cs = g_update_prefix | { 'type': 'virtual_district', 'id': id, 'boundary': new_boundary, 'center': new_center, 'nodes': new_nodes } + undo_cs = g_update_prefix | { 'type': 'virtual_district', 'id': id, 'boundary': old_boundary, 'center': old_center, 'nodes': old_nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_virtual_district(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + vd = get_virtual_district(name, op['id']) + if vd == {}: + return ChangeSet() + + if 'boundary' not in op: + op['boundary'] = vd['boundary'] + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'center' not in op: + op['center'] = vd['center'] + + if not is_node(name, op['center']): + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = vd['nodes'] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _set_virtual_district(name, cs)) + + +def _add_virtual_district(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + boundary = cs.operations[0]['boundary'] + + center = cs.operations[0]['center'] + f_center = f"'{center}'" + + nodes = cs.operations[0]['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'VD');" + redo_sql += f"insert into region_vd (id, center, nodes) values ('{id}', {f_center}, '{str_nodes}');" + + undo_sql = f"delete from region_vd where id = '{id}';" + undo_sql += f"delete from region where id = '{id}';" + + redo_cs = g_add_prefix | { 'type': 'virtual_district', 'id': id, 'boundary': boundary, 'center': center, 'nodes': nodes } + undo_cs = g_delete_prefix | { 'type': 'virtual_district', 'id': id } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_virtual_district(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + vd = get_virtual_district(name, op['id']) + if vd != {}: + return ChangeSet() + + if 'boundary' not in op: + return ChangeSet() + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'center' not in op: + return ChangeSet() + + if not is_node(name, op['center']): + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = [] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _add_virtual_district(name, cs)) + + +def _delete_virtual_district(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + vd = get_virtual_district(name, id) + boundary = vd['boundary'] + center = vd['center'] + f_center = f"'{center}'" + nodes = vd['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"delete from region_vd where id = '{id}';" + redo_sql += f"delete from region where id = '{id}';" + + undo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'VD');" + undo_sql += f"insert into region_vd (id, center, nodes) values ('{id}', {f_center}, '{str_nodes}');" + + redo_cs = g_delete_prefix | { 'type': 'virtual_district', 'id': id } + undo_cs = g_add_prefix | { 'type': 'virtual_district', 'id': id, 'boundary': boundary, 'center': center, 'nodes': nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_virtual_district(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + vd = get_virtual_district(name, op['id']) + if vd == {}: + return ChangeSet() + + return execute_command(name, _delete_virtual_district(name, cs)) + + +def get_all_virtual_district_ids(name: str) -> list[str]: + ids = [] + for row in read_all(name, f"select id from region_vd"): + ids.append(row['id']) + return ids + + +def get_all_virtual_districts(name: str) -> list[dict[str, Any]]: + result = [] + for id in get_all_virtual_district_ids(name): + result.append(get_virtual_district(name, id)) + return result diff --git a/app/native/wndb/s35_vd_cal.py b/app/native/wndb/s35_vd_cal.py new file mode 100644 index 0000000..b115814 --- /dev/null +++ b/app/native/wndb/s35_vd_cal.py @@ -0,0 +1,66 @@ +from .database import * +from .s0_base import get_node_links + + +def calculate_virtual_district(name: str, centers: list[str]) -> dict[str, list[Any]]: + write(name, 'delete from temp_vd_topology') + + # map node name to index + i = 0 + isolated_nodes = [] + node_index: dict[str, int] = {} + for row in read_all(name, 'select id from _node'): + node = str(row['id']) + if get_node_links(name, node) == []: + isolated_nodes.append(node) + continue + i += 1 + node_index[node] = i + + # build topology graph + pipes = read_all(name, 'select node1, node2, length from pipes') + for pipe in pipes: + source = node_index[str(pipe['node1'])] + target = node_index[str(pipe['node2'])] + cost = float(pipe['length']) + write(name, f"insert into temp_vd_topology (source, target, cost) values ({source}, {target}, {cost})") + pumps = read_all(name, 'select node1, node2 from pumps') + for pump in pumps: + source = node_index[str(pump['node1'])] + target = node_index[str(pump['node2'])] + write(name, f"insert into temp_vd_topology (source, target, cost) values ({source}, {target}, 0.0)") + valves = read_all(name, 'select node1, node2 from valves') + for valve in valves: + source = node_index[str(valve['node1'])] + target = node_index[str(valve['node2'])] + write(name, f"insert into temp_vd_topology (source, target, cost) values ({source}, {target}, 0.0)") + + # dijkstra distance + node_distance: dict[str, dict[str, Any]] = {} + for center in centers: + for node, index in node_index.items(): + if node == center: + node_distance[node] = { 'center': center, 'distance' : 0.0 } + continue + # TODO: check none + distance = float(read(name, f"select max(agg_cost) as distance from pgr_dijkstraCost('select id, source, target, cost from temp_vd_topology', {index}, {node_index[center]}, false)")['distance']) + if node not in node_distance: + node_distance[node] = { 'center': center, 'distance' : distance } + elif distance < node_distance[node]['distance']: + node_distance[node] = { 'center': center, 'distance' : distance } + + write(name, 'delete from temp_vd_topology') + + # reorganize the distance result + center_node: dict[str, list[str]] = {} + for node, value in node_distance.items(): + if value['center'] not in center_node: + center_node[value['center']] = [] + center_node[value['center']].append(node) + + vds: list[dict[str, Any]] = [] + + for center, value in center_node.items(): + vds.append({ 'center': center, 'nodes': value }) + + return { 'virtual_districts': vds, 'isolated_nodes': isolated_nodes } diff --git a/app/native/wndb/s35_vd_gen.py b/app/native/wndb/s35_vd_gen.py new file mode 100644 index 0000000..6a3bc72 --- /dev/null +++ b/app/native/wndb/s35_vd_gen.py @@ -0,0 +1,21 @@ +from .s32_region_util import calculate_boundary, inflate_boundary +from .s35_vd_cal import * +from .s35_vd import get_all_virtual_district_ids +from .batch_exe import execute_batch_command + +def generate_virtual_district(name: str, centers: list[str], inflate_delta: float = 0.5) -> ChangeSet: + cs = ChangeSet() + + for id in get_all_virtual_district_ids(name): + cs.delete({'type': 'virtual_district', 'id': id}) + + vds = calculate_virtual_district(name, centers)['virtual_districts'] + + for vd in vds: + center = vd['center'] + nodes = vd['nodes'] + boundary = calculate_boundary(name, nodes) + boundary = inflate_boundary(name, boundary, inflate_delta) + cs.add({ 'type': 'virtual_district', 'id': f"VD_{center}", 'boundary': boundary, 'center': center, 'nodes': nodes }) + + return execute_batch_command(name, cs) diff --git a/app/native/wndb/s36_wda.py b/app/native/wndb/s36_wda.py new file mode 100644 index 0000000..e69de29 diff --git a/app/native/wndb/s36_wda_cal.py b/app/native/wndb/s36_wda_cal.py new file mode 100644 index 0000000..4583993 --- /dev/null +++ b/app/native/wndb/s36_wda_cal.py @@ -0,0 +1,104 @@ +from .database import ChangeSet +from .s0_base import is_junction, get_nodes +from .s9_demands import get_demand +from .s32_region_util import Topology, get_nodes_in_region +from .batch_exe import execute_batch_command + + +DISTRIBUTION_TYPE_ADD = 'ADD' +DISTRIBUTION_TYPE_OVERRIDE = 'OVERRIDE' + + +def calculate_demand_to_nodes(name: str, demand: float, nodes: list[str]) -> dict[str, float]: + if len(nodes) == 0 or demand == 0.0: + return {} + + topology = Topology(name, nodes) + t_nodes = topology.nodes() + t_links = topology.links() + + length_sum = 0.0 + for value in t_links.values(): + length_sum += abs(value['length']) + + if length_sum <= 0.0: + return {} + + demand_per_length = demand / length_sum + + result: dict[str, float] = {} + for node, value in t_nodes.items(): + if not is_junction(name, node): + continue + demand_per_node = 0.0 + for link in value['links']: + demand_per_node += abs(t_links[link]['length']) * demand_per_length * 0.5 + result[node] = demand_per_node + + return result + + +def calculate_demand_to_region(name: str, demand: float, region: str) -> dict[str, float]: + nodes = get_nodes_in_region(name, region) + return calculate_demand_to_nodes(name, demand, nodes) + + +def calculate_demand_to_network(name: str, demand: float) -> dict[str, float]: + nodes = get_nodes(name) + return calculate_demand_to_nodes(name, demand, nodes) + + +def distribute_demand_to_nodes(name: str, demand: float, nodes: list[str], type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet: + if len(nodes) == 0 or demand == 0.0: + return ChangeSet() + if type != DISTRIBUTION_TYPE_ADD and type != DISTRIBUTION_TYPE_OVERRIDE: + return ChangeSet() + + topology = Topology(name, nodes) + t_nodes = topology.nodes() + t_links = topology.links() + + length_sum = 0.0 + for value in t_links.values(): + length_sum += abs(value['length']) + + if length_sum <= 0.0: + return ChangeSet() + + demand_per_length = demand / length_sum + + cs = ChangeSet() + + for node, value in t_nodes.items(): + if not is_junction(name, node): + continue + demand_per_node = 0.0 + for link in value['links']: + demand_per_node += abs(t_links[link]['length']) * demand_per_length * 0.5 + + ds = get_demand(name, node)['demands'] + if len(ds) == 0: + ds = [{'demand': demand_per_node, 'pattern': None, 'category': None}] + elif type == DISTRIBUTION_TYPE_ADD: + ds[0]['demand'] += demand_per_node + else: + ds[0]['demand'] = demand_per_node + cs.update({'type': 'demand', 'junction': node, 'demands': ds}) + + return execute_batch_command(name, cs) + + +def distribute_demand_to_region(name: str, demand: float, region: str, type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet: + nodes = get_nodes_in_region(name, region) + return distribute_demand_to_nodes(name, demand, nodes, type) + +def get_total_base_demand(name:str,region:str)->float: + nodes = get_nodes_in_region(name, region) + t_demands=0.0 + for node in nodes: + if not is_junction(name, node): + continue + ds = get_demand(name, node)['demands'] + t_demands= t_demands+ds[0]['demand'] + + return t_demands \ No newline at end of file diff --git a/app/native/wndb/s38_scada_info.py b/app/native/wndb/s38_scada_info.py new file mode 100644 index 0000000..3e932f9 --- /dev/null +++ b/app/native/wndb/s38_scada_info.py @@ -0,0 +1,42 @@ +from .database import * + + +def get_scada_info_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'type' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'x' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'query_api_id' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'associated_element_id' : {'type': 'str' , 'optional': False , 'readonly': True } } + + +def get_scada_info(name: str, id: str) -> dict[str, Any]: + si = try_read(name, f"select * from scada_info where id = '{id}'") + if si is None: + return {} + + d = {} + d['id'] = si['id'] + d['type'] = si['type'] + d['x'] = float(si['x_coor']) + d['y'] = float(si['y_coor']) + d['api_query_id'] = si['api_query_id'] + d['associated_element_id'] = si['associated_element_id'] + + return d + +def get_all_scada_info(name: str) -> list[dict[str, Any]]: + sis = read_all(name, f"select * from scada_info") + if sis is None: + return [] + + d = [] + for si in sis: + d.append({ 'id': si['id'], + 'type': si['type'], + 'x': float(si['x_coor']), + 'y': float(si['y_coor']), + 'api_query_id': si['api_query_id'], + 'associated_element_id': si['associated_element_id'] }) + + return d \ No newline at end of file diff --git a/app/native/wndb/s39_user.py b/app/native/wndb/s39_user.py new file mode 100644 index 0000000..3b4c37d --- /dev/null +++ b/app/native/wndb/s39_user.py @@ -0,0 +1,37 @@ +from .database import * +from .s0_base import * + +class User(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'user' + self.id = str(input['user_id']) + self.name = str(input['username']) + self.password = str(input['password']) + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'name': self.name, 'password': self.password } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def get_user_schema(name: str) -> dict[str, dict[Any, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'name' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'password' : {'type': 'str' , 'optional': False , 'readonly': False} } + +def get_user(name: str, user_name: str) -> dict[Any, Any]: + t = try_read(name, f"select * from users where username = '{user_name}'") + if t == None: + return {} + + d = {} + d['id'] = str(t['user_id']) + d['name'] = str(t['username']) + # d['password'] = str(t['password']) + + return d + +def get_all_users(name: str) -> list[dict[Any, Any]]: + return read_all(name, "select * from users") + diff --git a/app/native/wndb/s3_reservoirs.py b/app/native/wndb/s3_reservoirs.py new file mode 100644 index 0000000..181b707 --- /dev/null +++ b/app/native/wndb/s3_reservoirs.py @@ -0,0 +1,193 @@ +from .database import * +from .s0_base import * +from .s24_coordinates import * + + +def get_reservoir_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'x' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'head' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'pattern' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'links' : {'type': 'str_list' , 'optional': False , 'readonly': True } } + + +def get_reservoir(name: str, id: str) -> dict[str, Any]: + r = try_read(name, f"select * from reservoirs where id = '{id}'") + if r == None: + return {} + xy = get_node_coord(name, id) + d = {} + d['id'] = str(r['id']) + d['x'] = float(xy['x']) + d['y'] = float(xy['y']) + d['head'] = float(r['head']) + d['pattern'] = str(r['pattern']) if r['pattern'] != None else None + d['links'] = get_node_links(name, id) + return d + +# DingZQ, 2025-03-29 +def get_all_reservoirs(name: str) -> list[dict[str, Any]]: + rows = read_all(name, f"select * from reservoirs") + if rows == None: + return [] + + result = [] + for row in rows: + d = {} + id = str(row['id']) + xy = get_node_coord(name, id) + d['id'] = id + d['x'] = float(xy['x']) + d['y'] = float(xy['y']) + d['head'] = float(row['head']) if row['head'] != None else None + d['pattern'] = str(row['pattern']) if row['pattern'] != None else None + d['links'] = get_node_links(name, id) + result.append(d) + + return result + +class Reservoir(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'reservoir' + self.id = str(input['id']) + self.x = float(input['x']) + self.y = float(input['y']) + self.head = float(input['head']) + self.pattern = str(input['pattern']) if 'pattern' in input and input['pattern'] != None else None + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_head = self.head + self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'x': self.x, 'y': self.y, 'head': self.head, 'pattern': self.pattern } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_reservoir(name: str, cs: ChangeSet) -> DbChangeSet: + old = Reservoir(get_reservoir(name, cs.operations[0]['id'])) + raw_new = get_reservoir(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_reservoir_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Reservoir(raw_new) + + redo_sql = f"update reservoirs set head = {new.f_head}, pattern = {new.f_pattern} where id = {new.f_id};" + redo_sql += f"\n{sql_update_coord(new.id, new.x, new.y)}" + + undo_sql = sql_update_coord(old.id, old.x, old.y) + undo_sql += f"\nupdate reservoirs set head = {old.f_head}, pattern = {old.f_pattern} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_reservoir(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_reservoir(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_reservoir(name, cs)) + + +def _add_reservoir(name: str, cs: ChangeSet) -> DbChangeSet: + new = Reservoir(cs.operations[0]) + + redo_sql = f"insert into _node (id, type) values ({new.f_id}, {new.f_type});" + redo_sql += f"\ninsert into reservoirs (id, head, pattern) values ({new.f_id}, {new.f_head}, {new.f_pattern});" + redo_sql += f"\n{sql_insert_coord(new.id, new.x, new.y)}" + + undo_sql = sql_delete_coord(new.id) + undo_sql += f"\ndelete from reservoirs where id = {new.f_id};" + undo_sql += f"\ndelete from _node where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_reservoir(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_reservoir(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_reservoir(name, cs)) + + +def _delete_reservoir(name: str, cs: ChangeSet) -> DbChangeSet: + old = Reservoir(get_reservoir(name, cs.operations[0]['id'])) + + redo_sql = sql_delete_coord(old.id) + redo_sql += f"\ndelete from reservoirs where id = {old.f_id};" + redo_sql += f"\ndelete from _node where id = {old.f_id};" + + undo_sql = f"insert into _node (id, type) values ({old.f_id}, {old.f_type});" + undo_sql += f"\ninsert into reservoirs (id, head, pattern) values ({old.f_id}, {old.f_head}, {old.f_pattern});" + undo_sql += f"\n{sql_insert_coord(old.id, old.x, old.y)}" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_reservoir(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_reservoir(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_reservoir(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# id elev (pattern) ;desc +#-------------------------------------------------------------- + + +def inp_in_reservoir(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + id = str(tokens[0]) + head = float(tokens[1]) + pattern = str(tokens[2]) if num_without_desc >= 3 else None + pattern = f"'{pattern}'" if pattern != None else 'null' + desc = str(tokens[-1]) if has_desc else None + + return str(f"insert into _node (id, type) values ('{id}', 'reservoir');insert into reservoirs (id, head, pattern) values ('{id}', {head}, {pattern});") + + +def inp_out_reservoir(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from reservoirs') + for obj in objs: + id = obj['id'] + head = obj['head'] + pattern = obj['pattern'] if obj['pattern'] != None else '' + desc = ';' + lines.append(f'{id} {head} {pattern} {desc}') + return lines + + +def unset_reservoir_by_pattern(name: str, pattern: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select id from reservoirs where pattern = '{pattern}'") + for row in rows: + cs.append(g_update_prefix | {'type': 'reservoir', 'id': row['id'], 'pattern': None}) + + return cs diff --git a/app/native/wndb/s40_schema.py b/app/native/wndb/s40_schema.py new file mode 100644 index 0000000..4a646ee --- /dev/null +++ b/app/native/wndb/s40_schema.py @@ -0,0 +1,33 @@ +from .database import * +from .s0_base import * + + +def get_scheme_schema(name: str) -> dict[str, dict[Any, Any]]: + return { + "id": {"type": "str", "optional": False, "readonly": True}, + "name": {"type": "str", "optional": False, "readonly": False}, + "type": {"type": "str", "optional": False, "readonly": False}, + "create_time": {"type": "str", "optional": False, "readonly": True}, + "start_time": {"type": "str", "optional": False, "readonly": True}, + "detail": {"type": "str", "optional": False, "readonly": True}, + } + + +def get_scheme(name: str, schema_name: str) -> dict[Any, Any]: + t = try_read(name, f"select * from scheme_list where scheme_name = '{schema_name}'") + if t == None: + return {} + + d = {} + d["id"] = str(t["scheme_id"]) + d["name"] = str(t["scheme_name"]) + d["type"] = str(t["scheme_type"]) + d["create_time"] = str(t["create_time"]) + d["start_time"] = str(t["start_time"]) + d["detail"] = str(t["detail"]) + + return d + + +def get_all_schemes(name: str) -> list[dict[Any, Any]]: + return read_all(name, "select * from scheme_list") diff --git a/app/native/wndb/s41_pipe_risk_probability.py b/app/native/wndb/s41_pipe_risk_probability.py new file mode 100644 index 0000000..33f0fe9 --- /dev/null +++ b/app/native/wndb/s41_pipe_risk_probability.py @@ -0,0 +1,87 @@ +from .database import * +from .s0_base import * +import json + +def get_pipe_risk_probability_now(name: str, pipe_id: str) -> dict[str, Any]: + t = try_read(name, f"select * from pipe_risk_probability where pipeid = '{pipe_id}'") + if t == None: + return {} + + d = {} + d['pipeid'] = str(t['pipeid']) + d['pipeage'] = t['pipeage'] + d['risk_probability_now'] = t['risk_probability_now'] + + return d + +def get_pipe_risk_probability(name: str, pipe_id: str) -> dict[str, Any]: + t = try_read(name, f"select * from pipe_risk_probability where pipeid = '{pipe_id}'") + if t == None: + return {} + + d = {} + d['pipeid'] = t['pipeid'] + d['x'] = t['x'] + d['y'] = t['y'] + + return d + +def get_network_pipe_risk_probability_now(name: str) -> list[dict[str, Any]]: + pipe_risk_probability_list = [] + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select * from pipe_risk_probability") + for record in cur: + #pipe_risk_probability_list.append(record) + t = {} + t['pipeid'] = record['pipeid'] + t['pipeage'] = record['pipeage'] + t['risk_probability_now'] = record['risk_probability_now'] + pipe_risk_probability_list.append(t) + + return pipe_risk_probability_list + +def get_pipes_risk_probability(name: str, pipe_ids: list[str]) -> list[dict[str, Any]]: + pipe_risk_probability_list = [] + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select * from pipe_risk_probability") + for record in cur: + if record['pipeid'] in pipe_ids: + t = {} + t['pipeid'] = record['pipeid'] + t['x'] = record['x'] + t['y'] = record['y'] + pipe_risk_probability_list.append(t) + + return pipe_risk_probability_list + +def get_pipe_risk_probability_geometries(name: str) -> dict[str, Any]: + ''' + 获取管道的几何信息 + 返回一个字典,key 是管道的 id,value 是管道的几何信息 + 几何信息是一个字典,包含 start 和 end 两个 key,value 是管道的起点和终点的坐标 + ''' + pipe_risk_probability_geometries = {} + + key_pipeId = '编码' + # key_startnode = '上游节点' + # key_endnode = '下游节点' + key_geometry = 'geometry' + + with conn[name].cursor(row_factory=dict_row) as cur: + cur.execute(f"select *, ST_AsGeoJSON(geometry) AS {key_geometry} from gis_pipe") + + for record in cur: + id = record[key_pipeId] + geom = json.loads(record[key_geometry]) + + pipe_risk_probability_geometries[id] = { + 'points': geom['coordinates'] + } + + for col in record: + if col != key_geometry: + pipe_risk_probability_geometries[id][col] = record[col] + + # print(len(pipe_risk_probability_geometries)) + + return pipe_risk_probability_geometries \ No newline at end of file diff --git a/app/native/wndb/s42_sensor_placement.py b/app/native/wndb/s42_sensor_placement.py new file mode 100644 index 0000000..5ad8b2a --- /dev/null +++ b/app/native/wndb/s42_sensor_placement.py @@ -0,0 +1,7 @@ +from .database import * +from .s0_base import * +from .s42_sensor_placement import * +import json + +def get_all_sensor_placements(name: str) -> list[dict[Any, Any]]: + return read_all(name, "select * from sensor_placement") \ No newline at end of file diff --git a/app/native/wndb/s43_burst_locate_result.py b/app/native/wndb/s43_burst_locate_result.py new file mode 100644 index 0000000..ac26463 --- /dev/null +++ b/app/native/wndb/s43_burst_locate_result.py @@ -0,0 +1,6 @@ +from .database import * +from .s0_base import * +import json + +def get_all_burst_locate_results(name: str) -> list[dict[Any, Any]]: + return read_all(name, "select * from burst_locate_result") \ No newline at end of file diff --git a/app/native/wndb/s4_tanks.py b/app/native/wndb/s4_tanks.py new file mode 100644 index 0000000..306c9d7 --- /dev/null +++ b/app/native/wndb/s4_tanks.py @@ -0,0 +1,250 @@ +from .database import * +from .s0_base import * +from .s24_coordinates import * + + +OVERFLOW_YES = 'YES' +OVERFLOW_NO = 'NO' + + +def get_tank_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'x' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'y' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'elevation' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'init_level' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'min_level' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'max_level' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'diameter' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'min_vol' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'vol_curve' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'overflow' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'links' : {'type': 'str_list' , 'optional': False , 'readonly': True } } + + +def get_tank(name: str, id: str) -> dict[str, Any]: + t = try_read(name, f"select * from tanks where id = '{id}'") + if t == None: + return {} + xy = get_node_coord(name, id) + d = {} + d['id'] = str(t['id']) + d['x'] = float(xy['x']) + d['y'] = float(xy['y']) + d['elevation'] = float(t['elevation']) + d['init_level'] = float(t['init_level']) + d['min_level'] = float(t['min_level']) + d['max_level'] = float(t['max_level']) + d['diameter'] = float(t['diameter']) + d['min_vol'] = float(t['min_vol']) + d['vol_curve'] = str(t['vol_curve']) if t['vol_curve'] != None else None + d['overflow'] = str(t['overflow']) if t['overflow'] != None else None + d['links'] = get_node_links(name, id) + return d + +# DingZQ, 2025-03-29 +def get_all_tanks(name: str) -> list[dict[str, Any]]: + rows = read_all(name, f"select * from tanks") + if rows == None: + return [] + + result = [] + for row in rows: + d = {} + id = str(row['id']) + xy = get_node_coord(name, id) + d['id'] = id + d['x'] = float(xy['x']) + d['y'] = float(xy['y']) + d['elevation'] = float(row['elevation']) + d['init_level'] = float(row['init_level']) + d['min_level'] = float(row['min_level']) + d['max_level'] = float(row['max_level']) + d['diameter'] = float(row['diameter']) + d['min_vol'] = float(row['min_vol']) + d['vol_curve'] = str(row['vol_curve']) if row['vol_curve'] != None else None + d['overflow'] = str(row['overflow']) if row['overflow'] != None else None + d['links'] = get_node_links(name, id) + result.append(d) + + return result + +class Tank(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'tank' + self.id = str(input['id']) + self.x = float(input['x']) + self.y = float(input['y']) + self.elevation = float(input['elevation']) + self.init_level = float(input['init_level']) + self.min_level = float(input['min_level']) + self.max_level = float(input['max_level']) + self.diameter = float(input['diameter']) + self.min_vol = float(input['min_vol']) + self.vol_curve = str(input['vol_curve']) if 'vol_curve' in input and input['vol_curve'] != None else None + self.overflow = str(input['overflow']) if 'overflow' in input and input['overflow'] != None else None + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_elevation = self.elevation + self.f_init_level = self.init_level + self.f_min_level = self.min_level + self.f_max_level = self.max_level + self.f_diameter = self.diameter + self.f_min_vol = self.min_vol + self.f_vol_curve = f"'{self.vol_curve}'" if self.vol_curve != None else 'null' + self.f_overflow = f"'{self.overflow}'" if self.overflow != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'x': self.x, 'y': self.y, 'elevation': self.elevation, 'init_level': self.init_level, 'min_level': self.min_level, 'max_level': self.max_level, 'diameter': self.diameter, 'min_vol': self.min_vol, 'vol_curve': self.vol_curve, 'overflow': self.overflow } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_tank(name: str, cs: ChangeSet) -> DbChangeSet: + old = Tank(get_tank(name, cs.operations[0]['id'])) + raw_new = get_tank(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_tank_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Tank(raw_new) + + redo_sql = f"update tanks set elevation = {new.f_elevation}, init_level = {new.f_init_level}, min_level = {new.f_min_level}, max_level = {new.f_max_level}, diameter = {new.f_diameter}, min_vol = {new.f_min_vol}, vol_curve = {new.f_vol_curve}, overflow = {new.f_overflow} where id = {new.f_id};" + redo_sql += f"\n{sql_update_coord(new.id, new.x, new.y)}" + + undo_sql = sql_update_coord(old.id, old.x, old.y) + undo_sql += f"\nupdate tanks set elevation = {old.f_elevation}, init_level = {old.f_init_level}, min_level = {old.f_min_level}, max_level = {old.f_max_level}, diameter = {old.f_diameter}, min_vol = {old.f_min_vol}, vol_curve = {old.f_vol_curve}, overflow = {old.f_overflow} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_tank(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_tank(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_tank(name, cs)) + + +def _add_tank(name: str, cs: ChangeSet) -> DbChangeSet: + new = Tank(cs.operations[0]) + + redo_sql = f"insert into _node (id, type) values ({new.f_id}, {new.f_type});" + redo_sql += f"\ninsert into tanks (id, elevation, init_level, min_level, max_level, diameter, min_vol, vol_curve, overflow) values ({new.f_id}, {new.f_elevation}, {new.f_init_level}, {new.f_min_level}, {new.f_max_level}, {new.f_diameter}, {new.f_min_vol}, {new.f_vol_curve}, {new.f_overflow});" + redo_sql += f"\n{sql_insert_coord(new.id, new.x, new.y)}" + + undo_sql = sql_delete_coord(new.id) + undo_sql += f"\ndelete from tanks where id = {new.f_id};" + undo_sql += f"\ndelete from _node where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_tank(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_tank(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_tank(name, cs)) + + +def _delete_tank(name: str, cs: ChangeSet) -> DbChangeSet: + old = Tank(get_tank(name, cs.operations[0]['id'])) + + redo_sql = sql_delete_coord(old.id) + redo_sql += f"\ndelete from tanks where id = {old.f_id};" + redo_sql += f"\ndelete from _node where id = {old.f_id};" + + undo_sql = f"insert into _node (id, type) values ({old.f_id}, {old.f_type});" + undo_sql += f"\ninsert into tanks (id, elevation, init_level, min_level, max_level, diameter, min_vol, vol_curve, overflow) values ({old.f_id}, {old.f_elevation}, {old.f_init_level}, {old.f_min_level}, {old.f_max_level}, {old.f_diameter}, {old.f_min_vol}, {old.f_vol_curve}, {old.f_overflow});" + undo_sql += f"\n{sql_insert_coord(old.id, old.x, old.y)}" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_tank(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_tank(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_tank(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2] +# [IN] +# id elev initlevel minlevel maxlevel diam (minvol vcurve overflow) ;desc +# xxx +# * YES +# [OUT] +# id elev initlevel minlevel maxlevel diam minvol (vcurve overflow) ;desc +#-------------------------------------------------------------- +# [EPA3] +# id elev initlevel minlevel maxlevel diam minvol (vcurve) +#-------------------------------------------------------------- + + +def inp_in_tank(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + id = str(tokens[0]) + elevation = float(tokens[1]) + init_level = float(tokens[2]) + min_level = float(tokens[3]) + max_level = float(tokens[4]) + diameter = float(tokens[5]) + min_vol = float(tokens[6]) if num_without_desc >= 7 else 0.0 + vol_curve = str(tokens[7]) if num_without_desc >= 8 and tokens[7] != '*' else None + vol_curve = f"'{vol_curve}'" if vol_curve != None else 'null' + overflow = str(tokens[8].upper()) if num_without_desc >= 9 else None + overflow = f"'{overflow}'" if overflow != None else 'null' + desc = str(tokens[-1]) if has_desc else None + + return str(f"insert into _node (id, type) values ('{id}', 'tank');insert into tanks (id, elevation, init_level, min_level, max_level, diameter, min_vol, vol_curve, overflow) values ('{id}', {elevation}, {init_level}, {min_level}, {max_level}, {diameter}, {min_vol}, {vol_curve}, {overflow});") + + +def inp_out_tank(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from tanks') + for obj in objs: + id = obj['id'] + elevation = obj['elevation'] + init_level = obj['init_level'] + min_level = obj['min_level'] + max_level = obj['max_level'] + diameter = obj['diameter'] + min_vol = obj['min_vol'] + vol_curve = obj['vol_curve'] if obj['vol_curve'] != None else '' + overflow = obj['overflow'] if obj['overflow'] != None else '' + if vol_curve == '' and overflow != '': + vol_curve = '*' + desc = ';' + lines.append(f'{id} {elevation} {init_level} {min_level} {max_level} {diameter} {min_vol} {vol_curve} {overflow} {desc}') + return lines + + +def unset_tank_by_curve(name: str, curve: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select id from tanks where vol_curve = '{curve}'") + for row in rows: + cs.append(g_update_prefix | {'type': 'tank', 'id': row['id'], 'vol_curve': None}) + + return cs diff --git a/app/native/wndb/s5_pipes.py b/app/native/wndb/s5_pipes.py new file mode 100644 index 0000000..2930c3a --- /dev/null +++ b/app/native/wndb/s5_pipes.py @@ -0,0 +1,214 @@ +from .database import * +from .s0_base import * + + +PIPE_STATUS_OPEN = 'OPEN' +PIPE_STATUS_CLOSED = 'CLOSED' +PIPE_STATUS_CV = 'CV' + + +def get_pipe_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'node1' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'node2' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'length' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'diameter' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'roughness' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'minor_loss' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'status' : {'type': 'str' , 'optional': False , 'readonly': False} } + + +def get_pipe(name: str, id: str) -> dict[str, Any]: + p = try_read(name, f"select * from pipes where id = '{id}'") + if p == None: + return {} + d = {} + d['id'] = str(p['id']) + d['node1'] = str(p['node1']) + d['node2'] = str(p['node2']) + d['length'] = float(p['length']) + d['diameter'] = float(p['diameter']) + d['roughness'] = float(p['roughness']) + d['minor_loss'] = float(p['minor_loss']) + d['status'] = str(p['status']) + return d + +# DingZQ, 2025-03-29 +def get_all_pipes(name: str) -> list[dict[str, Any]]: + rows = read_all(name, f"select * from pipes") + if rows == None: + return [] + + result = [] + for row in rows: + d = {} + d['id'] = str(row['id']) + d['node1'] = str(row['node1']) + d['node2'] = str(row['node2']) + d['length'] = float(row['length']) + d['diameter'] = float(row['diameter']) + d['roughness'] = float(row['roughness']) + d['minor_loss'] = float(row['minor_loss']) + d['status'] = str(row['status']) + result.append(d) + + return result + +class Pipe(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'pipe' + self.id = str(input['id']) + self.node1 = str(input['node1']) + self.node2 = str(input['node2']) + self.length = float(input['length']) + self.diameter = float(input['diameter']) + self.roughness = float(input['roughness']) + self.minor_loss = float(input['minor_loss']) + self.status = str(input['status']) + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_node1 = f"'{self.node1}'" + self.f_node2 = f"'{self.node2}'" + self.f_length = self.length + self.f_diameter = self.diameter + self.f_roughness = self.roughness + self.f_minor_loss = self.minor_loss + self.f_status = f"'{self.status}'" + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'node1': self.node1, 'node2': self.node2, 'length': self.length, 'diameter': self.diameter, 'roughness': self.roughness, 'minor_loss': self.minor_loss, 'status': self.status } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_pipe(name: str, cs: ChangeSet) -> DbChangeSet: + old = Pipe(get_pipe(name, cs.operations[0]['id'])) + raw_new = get_pipe(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_pipe_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Pipe(raw_new) + + redo_sql = f"update pipes set node1 = {new.f_node1}, node2 = {new.f_node2}, length = {new.f_length}, diameter = {new.f_diameter}, roughness = {new.f_roughness}, minor_loss = {new.f_minor_loss}, status = {new.f_status} where id = {new.f_id};" + undo_sql = f"update pipes set node1 = {old.f_node1}, node2 = {old.f_node2}, length = {old.f_length}, diameter = {old.f_diameter}, roughness = {old.f_roughness}, minor_loss = {old.f_minor_loss}, status = {old.f_status} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_pipe(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pipe(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_pipe(name, cs)) + + +def _add_pipe(name: str, cs: ChangeSet) -> DbChangeSet: + new = Pipe(cs.operations[0]) + + redo_sql = f"insert into _link (id, type) values ({new.f_id}, {new.f_type});" + redo_sql += f"\ninsert into pipes (id, node1, node2, length, diameter, roughness, minor_loss, status) values ({new.f_id}, {new.f_node1}, {new.f_node2}, {new.f_length}, {new.f_diameter}, {new.f_roughness}, {new.f_minor_loss}, {new.f_status});" + + undo_sql = f"delete from pipes where id = {new.f_id};" + undo_sql += f"\ndelete from _link where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_pipe(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pipe(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_pipe(name, cs)) + + +def _delete_pipe(name: str, cs: ChangeSet) -> DbChangeSet: + old = Pipe(get_pipe(name, cs.operations[0]['id'])) + + redo_sql = f"delete from pipes where id = {old.f_id};" + redo_sql += f"\ndelete from _link where id = {old.f_id};" + + undo_sql = f"insert into _link (id, type) values ({old.f_id}, {old.f_type});" + undo_sql += f"\ninsert into pipes (id, node1, node2, length, diameter, roughness, minor_loss, status) values ({old.f_id}, {old.f_node1}, {old.f_node2}, {old.f_length}, {old.f_diameter}, {old.f_roughness}, {old.f_minor_loss}, {old.f_status});" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_pipe(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pipe(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_pipe(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3] +# [IN] +# id node1 node2 length diam rcoeff (lcoeff status) ;desc +# [OUT] +# id node1 node2 length diam rcoeff lcoeff (status) ;desc +#-------------------------------------------------------------- + + +def inp_in_pipe(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + id = str(tokens[0]) + node1 = str(tokens[1]) + node2 = str(tokens[2]) + length = float(tokens[3]) + diameter = float(tokens[4]) + roughness = float(tokens[5]) + minor_loss = float(tokens[6]) + # status is must-have, here fix input + status = str(tokens[7].upper()) if num_without_desc >= 8 else PIPE_STATUS_OPEN + desc = str(tokens[-1]) if has_desc else None + + return str(f"insert into _link (id, type) values ('{id}', 'pipe');insert into pipes (id, node1, node2, length, diameter, roughness, minor_loss, status) values ('{id}', '{node1}', '{node2}', {length}, {diameter}, {roughness}, {minor_loss}, '{status}');") + + +def inp_out_pipe(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from pipes') + for obj in objs: + id = obj['id'] + node1 = obj['node1'] + node2 = obj['node2'] + length = obj['length'] + diameter = obj['diameter'] + roughness = obj['roughness'] + minor_loss = obj['minor_loss'] + status = obj['status'] + desc = ';' + lines.append(f'{id} {node1} {node2} {length} {diameter} {roughness} {minor_loss} {status} {desc}') + return lines + + +'''def delete_pipe_by_node(name: str, node: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select id from pipes where node1 = '{node}' or node2 = '{node}'") + for row in rows: + cs.append(g_delete_prefix | {'type': 'pipe', 'id': row['id']}) + + return cs''' diff --git a/app/native/wndb/s6_pumps.py b/app/native/wndb/s6_pumps.py new file mode 100644 index 0000000..8ac4622 --- /dev/null +++ b/app/native/wndb/s6_pumps.py @@ -0,0 +1,231 @@ +from .database import * +from .s0_base import * + + +def get_pump_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'node1' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'node2' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'power' : {'type': 'float' , 'optional': True , 'readonly': False}, + 'head' : {'type': 'str' , 'optional': True , 'readonly': False}, + 'speed' : {'type': 'float' , 'optional': True , 'readonly': False}, + 'pattern' : {'type': 'str' , 'optional': True , 'readonly': False} } + + +def get_pump(name: str, id: str) -> dict[str, Any]: + p = try_read(name, f"select * from pumps where id = '{id}'") + if p == None: + return {} + d = {} + d['id'] = str(p['id']) + d['node1'] = str(p['node1']) + d['node2'] = str(p['node2']) + d['power'] = float(p['power']) if p['power'] != None else None + d['head'] = str(p['head']) if p['head'] != None else None + d['speed'] = float(p['speed']) if p['speed'] != None else None + d['pattern'] = str(p['pattern']) if p['pattern'] != None else None + return d + +# DingZQ, 2025-03-29 +def get_all_pumps(name: str) -> list[dict[str, Any]]: + rows = read_all(name, f"select * from pumps") + if rows == None: + return [] + + result = [] + for row in rows: + d = {} + d['id'] = str(row['id']) + d['node1'] = str(row['node1']) + d['node2'] = str(row['node2']) + d['power'] = float(row['power']) if row['power'] != None else None + d['head'] = str(row['head']) if row['head'] != None else None + d['speed'] = float(row['speed']) if row['speed'] != None else None + d['pattern'] = str(row['pattern']) if row['pattern'] != None else None + result.append(d) + + return result + + + +class Pump(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'pump' + self.id = str(input['id']) + self.node1 = str(input['node1']) + self.node2 = str(input['node2']) + self.power = float(input['power']) if 'power' in input and input['power'] != None else None + self.head = str(input['head']) if 'head' in input and input['head'] != None else None + self.speed = float(input['speed']) if 'speed' in input and input['speed'] != None else None + self.pattern = str(input['pattern']) if 'pattern' in input and input['pattern'] != None else None + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_node1 = f"'{self.node1}'" + self.f_node2 = f"'{self.node2}'" + self.f_power = self.power if self.power != None else 'null' + self.f_head = f"'{self.head}'" if self.head != None else 'null' + self.f_speed = self.speed if self.speed != None else 'null' + self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'node1': self.node1, 'node2': self.node2, 'power': self.power, 'head': self.head, 'speed': self.speed, 'pattern': self.pattern } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_pump(name: str, cs: ChangeSet) -> DbChangeSet: + old = Pump(get_pump(name, cs.operations[0]['id'])) + raw_new = get_pump(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_pump_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Pump(raw_new) + + redo_sql = f"update pumps set node1 = {new.f_node1}, node2 = {new.f_node2}, power = {new.f_power}, head = {new.f_head}, speed = {new.f_speed}, pattern = {new.f_pattern} where id = {new.f_id};" + undo_sql = f"update pumps set node1 = {old.f_node1}, node2 = {old.f_node2}, power = {old.f_power}, head = {old.f_head}, speed = {old.f_speed}, pattern = {old.f_pattern} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_pump(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pump(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_pump(name, cs)) + + +def _add_pump(name: str, cs: ChangeSet) -> DbChangeSet: + new = Pump(cs.operations[0]) + + redo_sql = f"insert into _link (id, type) values ({new.f_id}, {new.f_type});" + redo_sql += f"\ninsert into pumps (id, node1, node2, power, head, speed, pattern) values ({new.f_id}, {new.f_node1}, {new.f_node2}, {new.f_power}, {new.f_head}, {new.f_speed}, {new.f_pattern});" + + undo_sql = f"delete from pumps where id = {new.f_id};" + undo_sql += f"\ndelete from _link where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_pump(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pump(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_pump(name, cs)) + + +def _delete_pump(name: str, cs: ChangeSet) -> DbChangeSet: + old = Pump(get_pump(name, cs.operations[0]['id'])) + + redo_sql = f"delete from pumps where id = {old.f_id};" + redo_sql += f"\ndelete from _link where id = {old.f_id};" + + undo_sql = f"insert into _link (id, type) values ({old.f_id}, {old.f_type});" + undo_sql += f"\ninsert into pumps (id, node1, node2, power, head, speed, pattern) values ({old.f_id}, {old.f_node1}, {old.f_node2}, {old.f_power}, {old.f_head}, {old.f_speed}, {old.f_pattern});" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_pump(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_pump(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_pump(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# id node1 node2 KEYWORD value {KEYWORD value ...} ;desc +# where KEYWORD = [POWER,HEAD,PATTERN,SPEED] +#-------------------------------------------------------------- + + +def inp_in_pump(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + id = str(tokens[0]) + node1 = str(tokens[1]) + node2 = str(tokens[2]) + props = {} + for i in range(3, num_without_desc, 2): + props |= { tokens[i].lower(): tokens[i + 1] } + power = float(props['power']) if 'power' in props else None + power = power if power != None else 'null' + head = str(props['head']) if 'head' in props else None + head = f"'{head}'" if head != None else 'null' + speed = float(props['speed']) if 'speed' in props else None + speed = speed if speed != None else 'null' + pattern = str(props['pattern']) if 'pattern' in props else None + pattern = f"'{pattern}'" if pattern != None else 'null' + desc = str(tokens[-1]) if has_desc else None + + return str(f"insert into _link (id, type) values ('{id}', 'pump');insert into pumps (id, node1, node2, power, head, speed, pattern) values ('{id}', '{node1}', '{node2}', {power}, {head}, {speed}, {pattern});") + + +def inp_out_pump(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from pumps') + for obj in objs: + id = obj['id'] + node1 = obj['node1'] + node2 = obj['node2'] + power = f"POWER {obj['power']}" if obj['power'] != None else '' + head = f"HEAD {obj['head']}" if obj['head'] != None else '' + speed = f"SPEED {obj['speed']}" if obj['speed'] != None else '' + pattern = f"PATTERN {obj['pattern']}" if obj['pattern'] != None else '' + desc = ';' + lines.append(f'{id} {node1} {node2} {power} {head} {speed} {pattern} {desc}') + return lines + + +'''def delete_pump_by_node(name: str, node: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select id from pumps where node1 = '{node}' or node2 = '{node}'") + for row in rows: + cs.append(g_delete_prefix | {'type': 'pump', 'id': row['id']}) + + return cs''' + + +def unset_pump_by_curve(name: str, curve: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select * from pumps where head = '{curve}'") + for row in rows: + if row['power'] != None: + cs.append(g_update_prefix | {'type': 'pump', 'id': row['id'], 'head': None}) + else: # workaround to prevent pump deletion... and I don't want to remove constraint... + cs.append(g_update_prefix | {'type': 'pump', 'id': row['id'], 'head': None, 'power': 0.0}) + + return cs + + +def unset_pump_by_pattern(name: str, pattern: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select id from pumps where pattern = '{pattern}'") + for row in rows: + cs.append(g_update_prefix | {'type': 'pump', 'id': row['id'], 'pattern': None}) + + return cs diff --git a/app/native/wndb/s7_valves.py b/app/native/wndb/s7_valves.py new file mode 100644 index 0000000..3192088 --- /dev/null +++ b/app/native/wndb/s7_valves.py @@ -0,0 +1,210 @@ +from .database import * +from .s0_base import * + + +VALVES_TYPE_PRV = 'PRV' +VALVES_TYPE_PSV = 'PSV' +VALVES_TYPE_PBV = 'PBV' +VALVES_TYPE_FCV = 'FCV' +VALVES_TYPE_TCV = 'TCV' +VALVES_TYPE_GPV = 'GPV' + + +def get_valve_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'node1' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'node2' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'diameter' : {'type': 'float' , 'optional': False , 'readonly': False}, + 'v_type' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'setting' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'minor_loss' : {'type': 'float' , 'optional': False , 'readonly': False} } + + +def get_valve(name: str, id: str) -> dict[str, Any]: + p = try_read(name, f"select * from valves where id = '{id}'") + if p == None: + return {} + d = {} + d['id'] = str(p['id']) + d['node1'] = str(p['node1']) + d['node2'] = str(p['node2']) + d['diameter'] = float(p['diameter']) + d['v_type'] = str(p['v_type']) + d['setting'] = str(p['setting']) + d['minor_loss'] = float(p['minor_loss']) + return d + +def get_all_valves(name: str) -> list[dict[str, Any]]: + rows = read_all(name, f"select * from valves") + if rows == None: + return [] + + result = [] + for row in rows: + d = {} + d['id'] = str(row['id']) + d['node1'] = str(row['node1']) + d['node2'] = str(row['node2']) + d['diameter'] = float(row['diameter']) + d['v_type'] = str(row['v_type']) + d['setting'] = str(row['setting']) + d['minor_loss'] = float(row['minor_loss']) + result.append(d) + + return result + + + + +class Valve(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'valve' + self.id = str(input['id']) + self.node1 = str(input['node1']) + self.node2 = str(input['node2']) + self.diameter = float(input['diameter']) + self.v_type = str(input['v_type']) + self.setting = str(input['setting']) + self.minor_loss = float(input['minor_loss']) + + self.f_type = f"'{self.type}'" + self.f_id = f"'{self.id}'" + self.f_node1 = f"'{self.node1}'" + self.f_node2 = f"'{self.node2}'" + self.f_diameter = self.diameter + self.f_v_type = f"'{self.v_type}'" + self.f_setting = f"'{self.setting}'" + self.f_minor_loss = self.minor_loss + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id, 'node1': self.node1, 'node2': self.node2, 'diameter': self.diameter, 'v_type': self.v_type, 'setting': self.setting, 'minor_loss': self.minor_loss } + + def as_id_dict(self) -> dict[str, Any]: + return { 'type': self.type, 'id': self.id } + + +def _set_valve(name: str, cs: ChangeSet) -> DbChangeSet: + old = Valve(get_valve(name, cs.operations[0]['id'])) + raw_new = get_valve(name, cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_valve_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Valve(raw_new) + + redo_sql = f"update valves set node1 = {new.f_node1}, node2 = {new.f_node2}, diameter = {new.f_diameter}, v_type = {new.f_v_type}, setting = {new.f_setting}, minor_loss = {new.f_minor_loss} where id = {new.f_id};" + undo_sql = f"update valves set node1 = {old.f_node1}, node2 = {old.f_node2}, diameter = {old.f_diameter}, v_type = {old.f_v_type}, setting = {old.f_setting}, minor_loss = {old.f_minor_loss} where id = {old.f_id};" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_valve(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_valve(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _set_valve(name, cs)) + + +def _add_valve(name: str, cs: ChangeSet) -> DbChangeSet: + new = Valve(cs.operations[0]) + + redo_sql = f"insert into _link (id, type) values ({new.f_id}, {new.f_type});" + redo_sql += f"\ninsert into valves (id, node1, node2, diameter, v_type, setting, minor_loss) values ({new.f_id}, {new.f_node1}, {new.f_node2}, {new.f_diameter}, {new.f_v_type}, {new.f_setting}, {new.f_minor_loss});" + + undo_sql = f"delete from valves where id = {new.f_id};" + undo_sql += f"\ndelete from _link where id = {new.f_id};" + + redo_cs = g_add_prefix | new.as_dict() + undo_cs = g_delete_prefix | new.as_id_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_valve(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_valve(name, cs.operations[0]['id']) != {}: + return ChangeSet() + return execute_command(name, _add_valve(name, cs)) + + +def _delete_valve(name: str, cs: ChangeSet) -> DbChangeSet: + old = Valve(get_valve(name, cs.operations[0]['id'])) + + redo_sql = f"delete from valves where id = {old.f_id};" + redo_sql += f"\ndelete from _link where id = {old.f_id};" + + undo_sql = f"insert into _link (id, type) values ({old.f_id}, {old.f_type});" + undo_sql += f"\ninsert into valves (id, node1, node2, diameter, v_type, setting, minor_loss) values ({old.f_id}, {old.f_node1}, {old.f_node2}, {old.f_diameter}, {old.f_v_type}, {old.f_setting}, {old.f_minor_loss});" + + redo_cs = g_delete_prefix | old.as_id_dict() + undo_cs = g_add_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_valve(name: str, cs: ChangeSet) -> ChangeSet: + if 'id' not in cs.operations[0]: + return ChangeSet() + if get_valve(name, cs.operations[0]['id']) == {}: + return ChangeSet() + return execute_command(name, _delete_valve(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# id node1 node2 diam type setting (lcoeff lcurve) +# for GPV, setting is string = head curve id +# [NOT SUPPORT] for PCV, add loss curve if present +#-------------------------------------------------------------- + + +def inp_in_valve(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + id = str(tokens[0]) + node1 = str(tokens[1]) + node2 = str(tokens[2]) + diameter = float(tokens[3]) + v_type = str(tokens[4].upper()) + setting = str(tokens[5]) + minor_loss = float(tokens[6]) if len(tokens) >= 7 else 0.0 + desc = str(tokens[-1]) if has_desc else None + + return str(f"insert into _link (id, type) values ('{id}', 'valve');insert into valves (id, node1, node2, diameter, v_type, setting, minor_loss) values ('{id}', '{node1}', '{node2}', {diameter}, '{v_type}', '{setting}', {minor_loss});") + + +def inp_out_valve(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from valves') + for obj in objs: + id = obj['id'] + node1 = obj['node1'] + node2 = obj['node2'] + diameter = obj['diameter'] + v_type = obj['v_type'] + setting = obj['setting'] + minor_loss = obj['minor_loss'] + desc = ';' + lines.append(f'{id} {node1} {node2} {diameter} {v_type} {setting} {minor_loss} {desc}') + return lines + + +'''def delete_valve_by_node(name: str, node: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select id from valves where node1 = '{node}' or node2 = '{node}'") + for row in rows: + cs.append(g_delete_prefix | {'type': 'valve', 'id': row['id']}) + + return cs''' diff --git a/app/native/wndb/s8_tags.py b/app/native/wndb/s8_tags.py new file mode 100644 index 0000000..3a77576 --- /dev/null +++ b/app/native/wndb/s8_tags.py @@ -0,0 +1,142 @@ +from typing import Any +from .database import ChangeSet, execute_command, try_read, read_all, DbChangeSet, g_update_prefix + +TAG_TYPE_NODE = 'NODE' +TAG_TYPE_LINK = 'LINK' + +def get_tag_schema(name: str) -> dict[str, dict[str, Any]]: + return { 't_type' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'id' : {'type': 'str' , 'optional': False , 'readonly': False}, + 'tag' : {'type': 'str' , 'optional': True , 'readonly': False},} + + +def get_tags(name: str) -> list[dict[str, Any]]: + results: list[dict[str, Any]] = [] + rows = read_all(name, "select * from tags_node") + for row in rows: + tag = str(row['tag']) if row['tag'] != None else None + results.append({ 't_type': TAG_TYPE_NODE, 'id': str(row['id']), 'tag': tag }) + rows = read_all(name, "select * from tags_link") + for row in rows: + tag = str(row['tag']) if row['tag'] != None else None + results.append({ 't_type': TAG_TYPE_LINK, 'id': str(row['id']), 'tag': tag }) + return results + + +def get_tag(name: str, t_type: str, id: str) -> dict[str, Any]: + t = None + if t_type == TAG_TYPE_NODE: + t = try_read(name, f"select * from tags_node where id = '{id}'") + elif t_type == TAG_TYPE_LINK: + t = try_read(name, f"select * from tags_link where id = '{id}'") + if t is None: + return { 't_type': t_type, 'id': id, 'tag': None } + d = {} + d['t_type'] = t_type + d['id'] = str(t['id']) + d['tag'] = str(t['tag']) if t['tag'] is not None else None + return d + + +class Tag(object): + def __init__(self, input: dict[str, Any]) -> None: + self.type = 'tag' + self.t_type = str(input['t_type']) + self.id = str(input['id']) + self.tag = str(input['tag']) if 'tag' in input and input['tag'] != None else None + + self.f_type = f"'{self.type}'" + self.f_t_type = f"'{self.t_type}'" + self.f_id = f"'{self.id}'" + self.f_tag = f"'{self.tag}'" if self.tag != None else 'null' + + def as_dict(self) -> dict[str, Any]: + return { 'type': self.type, 't_type': self.t_type, 'id': self.id, 'tag': self.tag } + + +def _set_tag(name: str, cs: ChangeSet) -> DbChangeSet: + old = Tag(get_tag(name, cs.operations[0]['t_type'], cs.operations[0]['id'])) + raw_new = get_tag(name, cs.operations[0]['t_type'], cs.operations[0]['id']) + + new_dict = cs.operations[0] + schema = get_tag_schema(name) + for key, value in schema.items(): + if key in new_dict and not value['readonly']: + raw_new[key] = new_dict[key] + new = Tag(raw_new) + + table = '' + if cs.operations[0]['t_type'] == TAG_TYPE_NODE: + table = 'tags_node' + elif cs.operations[0]['t_type'] == TAG_TYPE_LINK: + table = 'tags_link' + else: + raise Exception('Only support NODE and Link') + + redo_sql = f"delete from {table} where id = {new.f_id};" + if new.tag is not None: + redo_sql += f"\ninsert into {table} (id, tag) values ({new.f_id}, {new.f_tag});" + + undo_sql = f"delete from {table} where id = {old.f_id};" + if old.tag is not None: + undo_sql += f"\ninsert into {table} (id, tag) values ({old.f_id}, {old.f_tag});" + + redo_cs = g_update_prefix | new.as_dict() + undo_cs = g_update_prefix | old.as_dict() + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_tag(name: str, cs: ChangeSet) -> ChangeSet: + if 't_type' not in cs.operations[0] or 'id' not in cs.operations[0] or 'tag' not in cs.operations[0]: + return ChangeSet() + return execute_command(name, _set_tag(name, cs)) + + +def inp_in_tag(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + t_type = str(tokens[0].upper()) + id = str(tokens[1]) + tag = str(tokens[2]) + + if t_type == TAG_TYPE_NODE: + return str(f"insert into tags_node (id, tag) values ('{id}', '{tag}');") + elif t_type == TAG_TYPE_LINK: + return str(f"insert into tags_link (id, tag) values ('{id}', '{tag}');") + return str('') + + +def inp_out_tag(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from tags_node') + for obj in objs: + t_type = TAG_TYPE_NODE + id = obj['id'] + tag = obj['tag'] + lines.append(f'{t_type} {id} {tag}') + objs = read_all(name, 'select * from tags_link') + for obj in objs: + t_type = TAG_TYPE_LINK + id = obj['id'] + tag = obj['tag'] + lines.append(f'{t_type} {id} {tag}') + return lines + + +def delete_tag_by_node(name: str, node: str) -> ChangeSet: + row = try_read(name, f"select * from tags_node where id = '{node}'") + if row is None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type': 'tag', 't_type': TAG_TYPE_NODE, 'id': node, 'tag': None }) + + +def delete_tag_by_link(name: str, link: str) -> ChangeSet: + row = try_read(name, f"select * from tags_link where id = '{link}'") + if row is None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type': 'tag', 't_type': TAG_TYPE_LINK, 'id': link, 'tag': None }) diff --git a/app/native/wndb/s9_demands.py b/app/native/wndb/s9_demands.py new file mode 100644 index 0000000..e1b8126 --- /dev/null +++ b/app/native/wndb/s9_demands.py @@ -0,0 +1,115 @@ +from .database import read_all, ChangeSet, DbChangeSet, g_update_prefix, execute_command, try_read +from typing import Any + +def get_demand_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'junction' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'demands' : {'type': 'list' , 'optional': False , 'readonly': False, + 'element': { 'demand' : {'type': 'float' , 'optional': False , 'readonly': False }, + 'pattern' : {'type': 'str' , 'optional': True , 'readonly': False }, + 'category': {'type': 'str' , 'optional': True , 'readonly': False }}}} + + +def get_demand(name: str, junction: str) -> dict[str, Any]: + des = read_all(name, f"select * from demands where junction = '{junction}' order by _order") + ds = [] + for r in des: + d = {} + d['demand'] = float(r['demand']) + d['pattern'] = str(r['pattern']) if r['pattern'] != None else None + d['category'] = str(r['category']) if r['category'] != None else None + ds.append(d) + return { 'junction': junction, 'demands': ds } + + +def _set_demand(name: str, cs: ChangeSet) -> DbChangeSet: + junction = cs.operations[0]['junction'] + old = get_demand(name, junction) + new = { 'junction': junction, 'demands': [] } + + f_junction = f"'{junction}'" + + # TODO: transaction ? + redo_sql = f"delete from demands where junction = {f_junction};" + for r in cs.operations[0]['demands']: + demand = float(r['demand']) + pattern = str(r['pattern']) if 'pattern' in r and r['pattern'] != None else None + category = str(r['category']) if 'category' in r and r['category'] != None else None + f_demand = demand + f_pattern = f"'{pattern}'" if pattern is not None else 'null' + f_category = f"'{category}'" if category is not None else 'null' + redo_sql += f"\ninsert into demands (junction, demand, pattern, category) values ({f_junction}, {f_demand}, {f_pattern}, {f_category});" + new['demands'].append({ 'demand': demand, 'pattern': pattern, 'category': category }) + + undo_sql = f"delete from demands where junction = {f_junction};" + for r in old['demands']: + demand = float(r['demand']) + pattern = str(r['pattern']) if 'pattern' in r and r['pattern'] != None else None + category = str(r['category']) if 'category' in r and r['category'] != None else None + f_demand = demand + f_pattern = f"'{pattern}'" if pattern is not None else 'null' + f_category = f"'{category}'" if category is not None else 'null' + undo_sql += f"\ninsert into demands (junction, demand, pattern, category) values ({f_junction}, {f_demand}, {f_pattern}, {f_category});" + + redo_cs = g_update_prefix | { 'type': 'demand' } | new + undo_cs = g_update_prefix | { 'type': 'demand' } | old + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_demand(name: str, cs: ChangeSet) -> ChangeSet: + return execute_command(name, _set_demand(name, cs)) + + +#-------------------------------------------------------------- +# [EPA2][EPA3][IN][OUT] +# node base_demand (pattern) ;category +#-------------------------------------------------------------- + + +def inp_in_demand(line: str) -> str: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + junction = str(tokens[0]) + demand = float(tokens[1]) + pattern = str(tokens[2]) if num_without_desc >= 3 else None + pattern = f"'{pattern}'" if pattern is not None else 'null' + category = str(tokens[3]) if num_without_desc >= 4 else None + category = f"'{category}'" if category is not None else 'null' + + return str(f"insert into demands (junction, demand, pattern, category) values ('{junction}', {demand}, {pattern}, {category});") + + +def inp_out_demand(name: str) -> list[str]: + lines = [] + objs = read_all(name, "select * from demands order by _order") + for obj in objs: + junction = obj['junction'] + demand = obj['demand'] + pattern = obj['pattern'] if obj['pattern'] is not None else '' + category = f";{obj['category']}" if obj['category'] is not None else ';' + lines.append(f'{junction} {demand} {pattern} {category}') + return lines + + +def delete_demand_by_junction(name: str, junction: str) -> ChangeSet: + row = try_read(name, f"select * from demands where junction = '{junction}'") + if row is None: + return ChangeSet() + return ChangeSet(g_update_prefix | {'type': 'demand', 'junction': junction, 'demands': []}) + + +def unset_demand_by_pattern(name: str, pattern: str) -> ChangeSet: + cs = ChangeSet() + + rows = read_all(name, f"select distinct junction from demands where pattern = '{pattern}'") + for row in rows: + ds = get_demand(name, row['junction']) + for d in ds['demands']: + d['pattern'] = None + cs.append(g_update_prefix | {'type': 'demand', 'junction': row['junction'], 'demands': ds['demands']}) + + return cs diff --git a/app/native/wndb/sections.py b/app/native/wndb/sections.py new file mode 100644 index 0000000..8c48a0d --- /dev/null +++ b/app/native/wndb/sections.py @@ -0,0 +1,90 @@ +s1_title = 'title' +s2_junction = 'junction' +s3_reservoir = 'reservoir' +s4_tank = 'tank' +s5_pipe = 'pipe' +s6_pump = 'pump' +s7_valve = 'valve' +s8_tag = 'tag' +s9_demand = 'demand' +s10_status = 'status' +s11_pattern = 'pattern' +s12_curve = 'curve' +s13_control = 'control' +s14_rule = 'rule' +s15_energy = 'energy' +s15_pump_energy = 'pump_energy' +s16_emitter = 'emitter' +s17_quality = 'quality' +s18_source = 'source' +s19_reaction = 'reaction' +s19_pipe_reaction = 'pipe_reaction' +s19_tank_reaction = 'tank_reaction' +s20_mixing = 'mixing' +s21_time = 'time' +s22_report = 'report' +s23_option = 'option' +s23_option_v3 = 'option_v3' +s24_coordinate = 'coordinate' +s25_vertex = 'vertex' +s26_label = 'label' +s27_backdrop = 'backdrop' +s28_end = 'end' +s29_scada_device = 'scada_device' +s30_scada_device_data = 'scada_device_data' +s31_scada_element = 'scada_element' +s32_region = 'region' +s33_dma = 'district_metering_area' +s34_sa = 'service_area' +s35_vd = 'virtual_district' + +TITLE = 'TITLE' +JUNCTIONS = 'JUNCTIONS' +RESERVOIRS = 'RESERVOIRS' +TANKS = 'TANKS' +PIPES = 'PIPES' +PUMPS = 'PUMPS' +VALVES = 'VALVES' +TAGS = 'TAGS' +DEMANDS = 'DEMANDS' +STATUS = 'STATUS' +PATTERNS = 'PATTERNS' +CURVES = 'CURVES' +CONTROLS = 'CONTROLS' +RULES = 'RULES' +ENERGY = 'ENERGY' +EMITTERS = 'EMITTERS' +QUALITY = 'QUALITY' +SOURCES = 'SOURCES' +REACTIONS = 'REACTIONS' +MIXING = 'MIXING' +TIMES = 'TIMES' +REPORT = 'REPORT' +OPTIONS = 'OPTIONS' +COORDINATES = 'COORDINATES' +VERTICES = 'VERTICES' +REGION='REGION' +BOUND='BOUND' +REGION_NODES='DATA_NODE_OF_REGION' +LABELS = 'LABELS' +BACKDROP = 'BACKDROP' +END = 'END' + +section_name = [TITLE, JUNCTIONS, RESERVOIRS, TANKS, PIPES, + PUMPS, VALVES, TAGS, DEMANDS, STATUS, + PATTERNS, CURVES, CONTROLS, RULES, ENERGY, + EMITTERS, QUALITY, SOURCES, REACTIONS, MIXING, + TIMES, REPORT, OPTIONS, COORDINATES, VERTICES, + REGION, BOUND, REGION_NODES, LABELS, BACKDROP, END] + +# DingZQ, 2025-02-04 +# 我们在从服务器调用run_project的时候 +# 会将 database的project内容dump成 epanet v2 的inp文件,然后调用 runepanet.exe 去计算结果 +# 其中上面的 SECTION : REGION, BOUND, REGION_NODES 在 epanet v2 中没有,是我们自己定制的 +# 所以需要将这些 section 从 section_name 中移除 +section_names_for_epanetv2 = [TITLE, JUNCTIONS, RESERVOIRS, TANKS, PIPES, + PUMPS, VALVES, TAGS, DEMANDS, STATUS, + PATTERNS, CURVES, CONTROLS, RULES, ENERGY, + EMITTERS, QUALITY, SOURCES, REACTIONS, MIXING, + TIMES, REPORT, OPTIONS, COORDINATES, VERTICES, + LABELS, BACKDROP, END] \ No newline at end of file diff --git a/app/services/__init__.py b/app/services/__init__.py new file mode 100644 index 0000000..645a38a --- /dev/null +++ b/app/services/__init__.py @@ -0,0 +1,36 @@ +from app.services.network_import import network_update, submit_scada_info +from app.services.scheme_management import ( + create_user, + delete_user, + scheme_name_exists, + store_scheme_info, + delete_scheme_info, + query_scheme_list, + upload_shp_to_pg, + submit_risk_probability_result, +) +from app.services.valve_isolation import analyze_valve_isolation +from app.services.simulation_ops import ( + project_management, + scheduling_simulation, + daily_scheduling_simulation, +) +from app.services.leakage_identifier import run_leakage_identification + +__all__ = [ + "network_update", + "submit_scada_info", + "create_user", + "delete_user", + "scheme_name_exists", + "store_scheme_info", + "delete_scheme_info", + "query_scheme_list", + "upload_shp_to_pg", + "submit_risk_probability_result", + "project_management", + "scheduling_simulation", + "daily_scheduling_simulation", + "analyze_valve_isolation", + "run_leakage_identification", +] diff --git a/app/services/burst_detection.py b/app/services/burst_detection.py new file mode 100644 index 0000000..59baf32 --- /dev/null +++ b/app/services/burst_detection.py @@ -0,0 +1,431 @@ +from __future__ import annotations + +from datetime import datetime +from typing import Any + +import pandas as pd + +from app.algorithms.burst_detection.burst_detector import BurstDetector +from app.infra.db.timescaledb.internal_queries import InternalQueries +from app.services.scheme_management import ( + query_burst_detection_scheme_detail, + query_burst_detection_schemes, + scheme_name_exists, + store_scheme_info, +) +from app.services.tjnetwork import get_all_scada_info + + +def run_burst_detection( + *, + network: str, + username: str, + observed_pressure_data: ( + pd.DataFrame + | dict[str, list[Any]] + | list[dict[str, Any]] + | list[list[Any]] + | None + ) = None, + points_per_day: int = 1440, + mu: int = 100, + iforest_params: dict[str, Any] | None = None, + scada_start: datetime | str | None = None, + scada_end: datetime | str | None = None, + sensor_nodes: list[str] | None = None, + scheme_name: str | None = None, + data_source: str = "monitoring", + simulation_scheme_name: str | None = None, + simulation_scheme_type: str | None = None, +) -> dict[str, Any]: + """ + 运行爆管侦测服务入口。 + + 调用方式二选一: + - 直接传 `observed_pressure_data` + - 或传 `scada_start/scada_end` 让后端自动查询 SCADA 压力数据 + + `observed_pressure_data` 支持格式: + - `pd.DataFrame` + 行表示时间点,列表示传感器;列名应为传感器/节点 ID。 + - `dict[str, list[Any]]` + 键为传感器/节点 ID,值为按时间顺序排列的压力序列。 + 例如:`{"J1": [101.2, 101.0], "J2": [99.8, 99.7]}`。 + - `list[dict[str, Any]]` + 每个元素代表一个时间点的多传感器观测。 + 例如:`[{"J1": 101.2, "J2": 99.8}, {"J1": 101.0, "J2": 99.7}]`。 + - `list[list[Any]]` + 二维数组式 JSON,格式为 `(时间点数, 传感器数)`。 + 这是最接近原始 `burst_detector` 示例代码的调用方式。 + + 数据约束: + - 统一要求“行=时间点,列=传感器”。 + - 总样本点数必须能被 `points_per_day` 整除。 + - 至少要有 2 天数据,即 `sample_count >= 2 * points_per_day`。 + - 若传入 `sensor_nodes`,输入数据必须包含这些列;SCADA 模式下也会只按这些节点取数。 + """ + if not network: + raise ValueError("network is required.") + + selected_sensor_nodes = ( + list(dict.fromkeys([node for node in (sensor_nodes or []) if node])) + if sensor_nodes + else None + ) + use_scada_source = scada_start is not None or scada_end is not None + + if use_scada_source: + scada_sensor_nodes = ( + selected_sensor_nodes + if selected_sensor_nodes is not None + else _get_pressure_sensor_nodes(network) + ) + if data_source == "simulation": + if not simulation_scheme_name: + raise ValueError("模拟方案模式必须提供 simulation_scheme_name。") + observed_df = _build_observed_pressure_from_simulation( + network=network, + sensor_nodes=scada_sensor_nodes, + scada_start=scada_start, + scada_end=scada_end, + simulation_scheme_name=simulation_scheme_name, + simulation_scheme_type=simulation_scheme_type, + ) + observed_input = observed_df + observed_source = "simulation_scheme_timerange" + else: + observed_df = _build_observed_pressure_from_scada( + network=network, + sensor_nodes=scada_sensor_nodes, + scada_start=scada_start, + scada_end=scada_end, + ) + observed_input = observed_df + observed_source = "backend_timerange" + else: + if observed_pressure_data is None: + raise ValueError( + "未提供 observed_pressure_data,且未提供 scada_start/scada_end。" + ) + observed_input = observed_pressure_data + observed_source = "request_payload" + + detector = BurstDetector( + mu=mu, + points_per_day=points_per_day, + iforest_params=iforest_params, + ) + result_df = detector.run_detection( + observed_input, + sensor_nodes=selected_sensor_nodes, + ) + resolved_sensor_nodes = list(result_df.attrs.get("sensor_nodes", [])) + rows = _serialize_result_rows(result_df) + payload: dict[str, Any] = { + "network": network, + "sensor_nodes": resolved_sensor_nodes, + "observed_source": observed_source, + "sample_count": int(result_df.attrs.get("sample_count", 0)), + "points_per_day": int(result_df.attrs.get("points_per_day", points_per_day)), + "day_count": int(result_df.attrs.get("day_count", len(result_df))), + "rows": rows, + "summary": _build_detection_summary(result_df), + } + if data_source == "simulation": + payload["data_source"] = "simulation" + payload["simulation_scheme"] = { + "name": simulation_scheme_name, + "type": simulation_scheme_type, + } + else: + payload["data_source"] = "monitoring" + + if use_scada_source: + payload["scada_window"] = { + "start": _to_datetime(scada_start).isoformat(), + "end": _to_datetime(scada_end).isoformat(), + } + if scheme_name: + _store_burst_detection_scheme( + network=network, + scheme_name=scheme_name, + username=username, + payload=payload, + mu=mu, + points_per_day=points_per_day, + iforest_params=detector.iforest_params, + ) + payload["scheme_name"] = scheme_name + return payload + + +def _build_observed_pressure_from_simulation( + *, + network: str, + sensor_nodes: list[str], + scada_start: datetime | str | None, + scada_end: datetime | str | None, + simulation_scheme_name: str | None, + simulation_scheme_type: str | None = None, +) -> pd.DataFrame: + if scada_start is None or scada_end is None: + raise ValueError("使用模拟方案查询时必须同时提供 scada_start 与 scada_end。") + + start_dt = _to_datetime(scada_start) + end_dt = _to_datetime(scada_end) + if start_dt >= end_dt: + raise ValueError("SCADA 时间窗非法:scada_start 必须早于 scada_end。") + + # Reuse burst_location logic partially here or call internal queries directly + # For burst detection, we need time series for all sensor nodes. + + # Check for missing nodes in simulation result if needed, but InternalQueries handles some of it. + # We assume sensor_nodes are valid pressure nodes. + + scheme_type = simulation_scheme_type or "burst_analysis" + + simulation_data = InternalQueries.query_scheme_simulation_by_ids_timerange( + db_name=network, + scheme_type=scheme_type, + scheme_name=simulation_scheme_name, + element_ids=sensor_nodes, + start_time=start_dt.isoformat(), + end_time=end_dt.isoformat(), + element_type="node", + field="pressure", + ) + + # simulation_data is {sensor_id: [{time, value}, ...]} + # Convert to DataFrame: index=time, columns=sensor_ids + + data_dict = {} + timestamps = set() + + for sensor_id in sensor_nodes: + records = simulation_data.get(sensor_id, []) + if not records: + continue + + # Convert records to Series with time index + ts_values = [] + ts_index = [] + for r in records: + if r.get("value") is not None: + ts_values.append(float(r["value"])) + ts_index.append(pd.to_datetime(r["time"])) + + if ts_values: + s = pd.Series(ts_values, index=ts_index) + data_dict[sensor_id] = s + timestamps.update(ts_index) + + if not data_dict: + raise ValueError("指定时间窗内未查询到模拟压力数据。") + + observation_df = pd.DataFrame(data_dict) + + # Handle missing timestamps if any (though simulation usually has uniform steps) + # Forward fill or interpolate might be needed if steps differ, but typically they align. + observation_df = observation_df.sort_index() + + # Fill NaN if any missing points for some sensors + observation_df = observation_df.fillna(method="ffill").fillna(method="bfill") + + if observation_df.empty: + raise ValueError("模拟压力数据无法构建观测矩阵。") + + return observation_df + + +def list_burst_detection_schemes( + network: str, + query_date: datetime | str | None = None, +) -> list[dict[str, Any]]: + parsed_date = _to_datetime(query_date).date() if query_date is not None else None + return query_burst_detection_schemes( + name=network, + network=network, + query_date=parsed_date, + ) + + +def get_burst_detection_scheme_detail(network: str, scheme_name: str) -> dict[str, Any]: + result = query_burst_detection_scheme_detail(network, scheme_name) + if not result: + raise ValueError(f"未找到爆管侦测方案: {scheme_name}") + return result + + +def _store_burst_detection_scheme( + *, + network: str, + scheme_name: str, + username: str, + payload: dict[str, Any], + mu: int, + points_per_day: int, + iforest_params: dict[str, Any], +) -> None: + if scheme_name_exists(network, scheme_name): + raise ValueError(f"方案名称已存在: {scheme_name}") + + now_iso = datetime.now().isoformat() + scheme_detail = { + "network": network, + "sensor_nodes": payload.get("sensor_nodes", []), + "observed_source": payload.get("observed_source"), + "scada_window": payload.get("scada_window"), + "algorithm_params": { + "mu": mu, + "points_per_day": points_per_day, + "iforest_params": iforest_params, + }, + "result_summary": payload.get("summary", {}), + "result_payload": payload, + } + store_scheme_info( + name=network, + scheme_name=scheme_name, + scheme_type="burst_detection", + username=username, + scheme_start_time=now_iso, + scheme_detail=scheme_detail, + ) + + +def _serialize_result_rows(result_df: pd.DataFrame) -> list[dict[str, Any]]: + rows: list[dict[str, Any]] = [] + for row in result_df.to_dict(orient="records"): + rows.append( + { + "Day": int(row["Day"]), + "Score": float(row["Score"]), + "Prediction": int(row["Prediction"]), + "IsBurst": bool(row["IsBurst"]), + } + ) + return rows + + +def _build_detection_summary(result_df: pd.DataFrame) -> dict[str, Any]: + rows = _serialize_result_rows(result_df) + if not rows: + raise ValueError("爆管侦测结果为空。") + + score_series = result_df["Score"] + most_anomalous_index = int(score_series.idxmin()) + latest_row = rows[-1] + anomaly_days = [row["Day"] for row in rows if row["IsBurst"]] + + return { + "burst_detected": bool(latest_row["IsBurst"]), + "latest_day": latest_row, + "most_anomalous_day": int(result_df.iloc[most_anomalous_index]["Day"]), + "anomaly_days": anomaly_days, + "anomaly_day_count": len(anomaly_days), + "latest_sensor_rankings": _build_latest_sensor_rankings(result_df), + } + + +def _build_latest_sensor_rankings(result_df: pd.DataFrame) -> list[dict[str, Any]]: + feature_matrix = result_df.attrs.get("high_freq_features") + sensor_nodes = list(result_df.attrs.get("sensor_nodes", [])) + if feature_matrix is None or len(sensor_nodes) == 0: + return [] + + latest_values = feature_matrix[-1] + ranking = sorted( + zip(sensor_nodes, latest_values, strict=False), + key=lambda item: item[1], + ) + return [ + { + "sensor_node": sensor_id, + "latest_high_frequency_value": float(value), + } + for sensor_id, value in ranking[: min(10, len(ranking))] + ] + + +def _get_pressure_sensor_nodes(network: str) -> list[str]: + sensor_nodes: list[str] = [] + for item in get_all_scada_info(network): + if str(item.get("type", "")).lower() != "pressure": + continue + node_id = item.get("associated_element_id") + if isinstance(node_id, str) and node_id: + sensor_nodes.append(node_id) + sensor_nodes = list(dict.fromkeys(sensor_nodes)) + if not sensor_nodes: + raise ValueError("未找到压力传感器对应节点(scada_info.type=pressure)。") + return sensor_nodes + + +def _build_observed_pressure_from_scada( + *, + network: str, + sensor_nodes: list[str], + scada_start: datetime | str | None, + scada_end: datetime | str | None, +) -> pd.DataFrame: + if scada_start is None or scada_end is None: + raise ValueError("使用后端 SCADA 查询时必须同时提供 scada_start 与 scada_end。") + + start_dt = _to_datetime(scada_start) + end_dt = _to_datetime(scada_end) + if start_dt >= end_dt: + raise ValueError("SCADA 时间窗非法:scada_start 必须早于 scada_end。") + + node_query_id: dict[str, str] = {} + for item in get_all_scada_info(network): + if str(item.get("type", "")).lower() != "pressure": + continue + node_id = item.get("associated_element_id") + query_id = item.get("api_query_id") + if ( + isinstance(node_id, str) + and node_id + and isinstance(query_id, str) + and query_id + ): + node_query_id[node_id] = query_id + + missing_nodes = [node_id for node_id in sensor_nodes if node_id not in node_query_id] + if missing_nodes: + preview = ", ".join(missing_nodes[:10]) + raise ValueError(f"未找到可用于压力观测的 SCADA api_query_id: {preview}") + + query_ids = [node_query_id[node_id] for node_id in sensor_nodes] + scada_data = InternalQueries.query_scada_by_ids_timerange( + db_name=network, + device_ids=query_ids, + start_time=start_dt.isoformat(), + end_time=end_dt.isoformat(), + ) + + available_lengths = [ + len(scada_data.get(query_id, [])) + for query_id in query_ids + if len(scada_data.get(query_id, [])) > 0 + ] + if not available_lengths: + raise ValueError("指定时间窗内未查询到压力 SCADA 数据。") + + min_len = min(available_lengths) + observation_df = pd.DataFrame() + for node_id in sensor_nodes: + query_id = node_query_id[node_id] + records = scada_data.get(query_id, [])[:min_len] + if len(records) < min_len: + continue + observation_df[node_id] = [float(item["value"]) for item in records] + + if observation_df.empty: + raise ValueError("SCADA 压力数据无法构建观测矩阵。") + return observation_df + + +def _to_datetime(value: datetime | str) -> datetime: + if isinstance(value, datetime): + return value + return datetime.fromisoformat(value) diff --git a/app/services/burst_location.py b/app/services/burst_location.py new file mode 100644 index 0000000..3892ca2 --- /dev/null +++ b/app/services/burst_location.py @@ -0,0 +1,659 @@ +from __future__ import annotations + +import os +from datetime import datetime +from typing import Any + +import pandas as pd + +from app.algorithms.burst_location import run_burst_location +from app.infra.db.timescaledb.internal_queries import InternalQueries +from app.services.scheme_management import ( + query_burst_location_scheme_detail, + query_burst_location_schemes, + scheme_name_exists, + store_scheme_info, +) +from app.services.tjnetwork import dump_inp, get_all_scada_info + +SeriesInput = pd.Series | dict[str, Any] | list[dict[str, Any]] +FLOW_SCADA_TYPES = {"pipe_flow", "flow", "demand"} +SIMULATION_DATA_SOURCES = {"monitoring", "simulation"} +DEFAULT_SIMULATION_SCHEME_TYPE = "burst_analysis" + + +def _normalize_series(data: SeriesInput, field_name: str) -> pd.Series: + if isinstance(data, pd.Series): + series = data.copy() + elif isinstance(data, dict): + series = pd.Series(data, dtype=float) + elif isinstance(data, list): + if len(data) == 0: + return pd.Series(dtype=float) + frame = pd.DataFrame(data) + if not {"id", "value"}.issubset(frame.columns): + raise ValueError(f"{field_name} list item must include 'id' and 'value'.") + series = pd.Series( + frame["value"].values, index=frame["id"].astype(str).values, dtype=float + ) + else: + raise ValueError(f"Unsupported data format for {field_name}.") + + series.index = series.index.map(str) + return pd.to_numeric(series, errors="raise") + + +def run_burst_location_by_network( + *, + network: str, + username: str, + data_source: str = "monitoring", + burst_leakage: float, + pressure_scada_ids: list[str] | None = None, + burst_pressure: SeriesInput | None = None, + normal_pressure: SeriesInput | None = None, + flow_scada_ids: list[str] | None = None, + burst_flow: SeriesInput | None = None, + normal_flow: SeriesInput | None = None, + min_dpressure: float = 2.0, + basic_pressure: float = 10.0, + scada_burst_start: datetime | str | None = None, + scada_burst_end: datetime | str | None = None, + use_scada_flow: bool = False, + scheme_name: str | None = None, + simulation_scheme_name: str | None = None, + simulation_scheme_type: str | None = None, +) -> dict[str, Any]: + if not network: + raise ValueError("network is required.") + normalized_data_source = _normalize_data_source( + data_source, simulation_scheme_name=simulation_scheme_name + ) + resolved_simulation_scheme_type = ( + simulation_scheme_type or DEFAULT_SIMULATION_SCHEME_TYPE + ) + + selected_pressure_ids = ( + _dedupe_ids(pressure_scada_ids) + if pressure_scada_ids + else _get_sensor_nodes(network, data_type="pressure") + ) + if not selected_pressure_ids: + raise ValueError("未提供有效压力传感器,且系统未识别到可用压力传感器。") + + use_scada_pressure = any( + value is not None + for value in [ + scada_burst_start, + scada_burst_end, + ] + ) + if use_scada_pressure: + burst_start_dt, burst_end_dt = _validate_scada_windows( + scada_burst_start=scada_burst_start, + scada_burst_end=scada_burst_end, + ) + if normalized_data_source == "simulation": + if not simulation_scheme_name: + raise ValueError("模拟方案模式必须提供 simulation_scheme_name。") + ( + burst_pressure_series, + burst_pressure_samples, + ) = _build_observed_series_from_simulation( + network=network, + sensor_ids=selected_pressure_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="pressure", + series_name="burst_pressure", + simulation_source="scheme", + simulation_scheme_name=simulation_scheme_name, + simulation_scheme_type=resolved_simulation_scheme_type, + ) + ( + normal_pressure_series, + normal_pressure_samples, + ) = _build_observed_series_from_simulation( + network=network, + sensor_ids=selected_pressure_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="pressure", + series_name="normal_pressure", + simulation_source="realtime", + simulation_scheme_name=None, + simulation_scheme_type=resolved_simulation_scheme_type, + ) + observed_source = "simulation_scheme_burst_realtime_normal_timerange" + else: + ( + burst_pressure_series, + burst_pressure_samples, + ) = _build_observed_series_from_scada( + network=network, + sensor_ids=selected_pressure_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="pressure", + series_name="burst_pressure", + ) + ( + normal_pressure_series, + normal_pressure_samples, + ) = _build_observed_series_from_simulation( + network=network, + sensor_ids=selected_pressure_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="pressure", + series_name="normal_pressure", + simulation_source="realtime", + simulation_scheme_name=None, + simulation_scheme_type=resolved_simulation_scheme_type, + ) + observed_source = "scada_burst_realtime_normal_timerange" + else: + if burst_pressure is None or normal_pressure is None: + raise ValueError( + "未提供 burst_pressure/normal_pressure,且未提供完整 SCADA 时间窗参数。" + ) + burst_pressure_series = _normalize_series(burst_pressure, "burst_pressure") + normal_pressure_series = _normalize_series(normal_pressure, "normal_pressure") + burst_pressure_samples = 1 + normal_pressure_samples = 1 + observed_source = "request_payload" + burst_start_dt = burst_end_dt = None + + selected_flow_ids: list[str] | None = None + burst_flow_series: pd.Series | None = None + normal_flow_series: pd.Series | None = None + use_flow_scada_source = use_scada_pressure and ( + use_scada_flow or flow_scada_ids is not None + ) + if use_flow_scada_source: + selected_flow_ids = ( + _dedupe_ids(flow_scada_ids) + if flow_scada_ids is not None + else _get_sensor_nodes(network, data_type="flow") + ) + if not selected_flow_ids: + raise ValueError("未找到可用流量传感器,无法从 SCADA 查询流量数据。") + if normalized_data_source == "simulation": + if not simulation_scheme_name: + raise ValueError("模拟方案模式必须提供 simulation_scheme_name。") + burst_flow_series, burst_flow_samples = ( + _build_observed_series_from_simulation( + network=network, + sensor_ids=selected_flow_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="flow", + series_name="burst_flow", + simulation_source="scheme", + simulation_scheme_name=simulation_scheme_name, + simulation_scheme_type=resolved_simulation_scheme_type, + ) + ) + normal_flow_series, normal_flow_samples = ( + _build_observed_series_from_simulation( + network=network, + sensor_ids=selected_flow_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="flow", + series_name="normal_flow", + simulation_source="realtime", + simulation_scheme_name=None, + simulation_scheme_type=resolved_simulation_scheme_type, + ) + ) + else: + burst_flow_series, burst_flow_samples = _build_observed_series_from_scada( + network=network, + sensor_ids=selected_flow_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="flow", + series_name="burst_flow", + ) + normal_flow_series, normal_flow_samples = ( + _build_observed_series_from_simulation( + network=network, + sensor_ids=selected_flow_ids, + start_dt=burst_start_dt, + end_dt=burst_end_dt, + data_type="flow", + series_name="normal_flow", + simulation_source="realtime", + simulation_scheme_name=None, + simulation_scheme_type=resolved_simulation_scheme_type, + ) + ) + else: + if flow_scada_ids is not None: + selected_flow_ids = _dedupe_ids(flow_scada_ids) + burst_flow_series = ( + _normalize_series(burst_flow, "burst_flow") + if burst_flow is not None + else None + ) + normal_flow_series = ( + _normalize_series(normal_flow, "normal_flow") + if normal_flow is not None + else None + ) + burst_flow_samples = 1 if burst_flow_series is not None else 0 + normal_flow_samples = 1 if normal_flow_series is not None else 0 + + inp_path = _prepare_burst_inp(network) + result = run_burst_location( + wn_inp_path=inp_path, + pressure_scada_ids=selected_pressure_ids, + burst_pressure=burst_pressure_series, + normal_pressure=normal_pressure_series, + burst_leakage=burst_leakage, + flow_scada_ids=selected_flow_ids, + burst_flow=burst_flow_series, + normal_flow=normal_flow_series, + min_dpressure=min_dpressure, + basic_pressure=basic_pressure, + ) + + payload: dict[str, Any] = { + **result, + "network": network, + "data_source": normalized_data_source, + "pressure_scada_ids": selected_pressure_ids, + "flow_scada_ids": selected_flow_ids or [], + "observed_source": observed_source, + "pressure_samples": { + "burst": burst_pressure_samples, + "normal": normal_pressure_samples, + }, + "flow_samples": {"burst": burst_flow_samples, "normal": normal_flow_samples}, + "burst_leakage": burst_leakage, + "min_dpressure": min_dpressure, + "basic_pressure": basic_pressure, + } + if use_scada_pressure: + payload["scada_window"] = { + "burst_start": burst_start_dt.isoformat(), + "burst_end": burst_end_dt.isoformat(), + } + if normalized_data_source == "simulation": + payload["simulation_scheme"] = { + "name": simulation_scheme_name, + "type": resolved_simulation_scheme_type, + } + if scheme_name: + _store_burst_scheme( + network=network, + scheme_name=scheme_name, + username=username, + payload=payload, + burst_leakage=burst_leakage, + min_dpressure=min_dpressure, + basic_pressure=basic_pressure, + ) + return payload + + +def list_burst_location_schemes( + network: str, query_date: datetime | str | None = None +) -> list[dict[str, Any]]: + parsed_date = _to_datetime(query_date).date() if query_date is not None else None + return query_burst_location_schemes( + name=network, network=network, query_date=parsed_date + ) + + +def get_burst_location_scheme_detail(network: str, scheme_name: str) -> dict[str, Any]: + result = query_burst_location_scheme_detail(network, scheme_name) + if not result: + raise ValueError(f"未找到爆管定位方案: {scheme_name}") + return result + + +def _store_burst_scheme( + *, + network: str, + scheme_name: str, + username: str, + payload: dict[str, Any], + burst_leakage: float, + min_dpressure: float, + basic_pressure: float, +) -> None: + if scheme_name_exists(network, scheme_name): + raise ValueError(f"方案名称已存在: {scheme_name}") + + now_iso = datetime.now().isoformat() + scheme_detail = { + "network": network, + "pressure_scada_ids": payload.get("pressure_scada_ids", []), + "flow_scada_ids": payload.get("flow_scada_ids", []), + "observed_source": payload.get("observed_source"), + "algorithm_params": { + "burst_leakage": burst_leakage, + "min_dpressure": min_dpressure, + "basic_pressure": basic_pressure, + }, + "scada_window": payload.get("scada_window"), + "result_summary": { + "located_pipe": payload.get("located_pipe"), + "simulation_times": payload.get("simulation_times"), + "similarity_mode": payload.get("similarity_mode"), + }, + "result_payload": payload, + } + store_scheme_info( + name=network, + scheme_name=scheme_name, + scheme_type="burst_location", + username=username, + scheme_start_time=now_iso, + scheme_detail=scheme_detail, + ) + + +def _validate_scada_windows( + *, + scada_burst_start: datetime | str | None, + scada_burst_end: datetime | str | None, +) -> tuple[datetime, datetime]: + values = [scada_burst_start, scada_burst_end] + if any(v is None for v in values): + raise ValueError( + "使用后端 SCADA 查询时,必须同时提供 scada_burst_start/scada_burst_end。" + ) + burst_start_dt = _to_datetime(scada_burst_start) + burst_end_dt = _to_datetime(scada_burst_end) + if burst_start_dt >= burst_end_dt: + raise ValueError( + "爆管时段 SCADA 时间窗非法:scada_burst_start 必须早于 scada_burst_end。" + ) + return burst_start_dt, burst_end_dt + + +def _build_observed_series_from_scada( + *, + network: str, + sensor_ids: list[str], + start_dt: datetime, + end_dt: datetime, + data_type: str, + series_name: str, +) -> tuple[pd.Series, int]: + scada_mapping = _build_scada_mapping(network=network, data_type=data_type) + missing_ids = [ + sensor_id for sensor_id in sensor_ids if sensor_id not in scada_mapping + ] + if missing_ids: + preview = ", ".join(missing_ids[:10]) + raise ValueError(f"{series_name} 缺少可用 SCADA 映射: {preview}") + + query_ids = [scada_mapping[sensor_id] for sensor_id in sensor_ids] + scada_data = InternalQueries.query_scada_by_ids_timerange( + db_name=network, + device_ids=query_ids, + start_time=start_dt.isoformat(), + end_time=end_dt.isoformat(), + ) + values: dict[str, float] = {} + sample_counts: list[int] = [] + for sensor_id, query_id in zip(sensor_ids, query_ids): + records = scada_data.get(query_id, []) + numeric_values = [ + float(item["value"]) for item in records if item.get("value") is not None + ] + if not numeric_values: + raise ValueError(f"{series_name} 在时间窗内无有效数据: {sensor_id}") + values[sensor_id] = float(sum(numeric_values) / len(numeric_values)) + sample_counts.append(len(numeric_values)) + + return pd.Series(values, dtype=float), min(sample_counts) + + +def _build_observed_series_from_simulation( + *, + network: str, + sensor_ids: list[str], + start_dt: datetime, + end_dt: datetime, + data_type: str, + series_name: str, + simulation_source: str, + simulation_scheme_name: str | None, + simulation_scheme_type: str, +) -> tuple[pd.Series, int]: + sensor_metadata = _build_sensor_metadata(network=network, data_type=data_type) + missing_ids = [ + sensor_id for sensor_id in sensor_ids if sensor_id not in sensor_metadata + ] + if missing_ids: + preview = ", ".join(missing_ids[:10]) + raise ValueError(f"{series_name} 缺少可用 SCADA 映射: {preview}") + + simulation_data = _query_simulation_data_by_sensor_ids( + network=network, + sensor_ids=sensor_ids, + sensor_metadata=sensor_metadata, + start_dt=start_dt, + end_dt=end_dt, + data_type=data_type, + simulation_source=simulation_source, + simulation_scheme_name=simulation_scheme_name, + simulation_scheme_type=simulation_scheme_type, + ) + values: dict[str, float] = {} + sample_counts: list[int] = [] + for sensor_id in sensor_ids: + records = simulation_data.get(sensor_id, []) + numeric_values = [ + float(item["value"]) for item in records if item.get("value") is not None + ] + if not numeric_values: + raise ValueError(f"{series_name} 在时间窗内无有效模拟数据: {sensor_id}") + values[sensor_id] = float(sum(numeric_values) / len(numeric_values)) + sample_counts.append(len(numeric_values)) + + return pd.Series(values, dtype=float), min(sample_counts) + + +def _query_simulation_data_by_sensor_ids( + *, + network: str, + sensor_ids: list[str], + sensor_metadata: dict[str, dict[str, str]], + start_dt: datetime, + end_dt: datetime, + data_type: str, + simulation_source: str, + simulation_scheme_name: str | None, + simulation_scheme_type: str, +) -> dict[str, list[dict[str, Any]]]: + if simulation_source not in {"scheme", "realtime"}: + raise ValueError(f"Unsupported simulation_source: {simulation_source}") + + result: dict[str, list[dict[str, Any]]] = { + sensor_id: [] for sensor_id in sensor_ids + } + if data_type == "pressure": + result.update( + _query_simulation_values( + network=network, + element_ids=sensor_ids, + element_type="node", + field="pressure", + start_dt=start_dt, + end_dt=end_dt, + simulation_source=simulation_source, + simulation_scheme_name=simulation_scheme_name, + simulation_scheme_type=simulation_scheme_type, + ) + ) + return result + + if data_type != "flow": + raise ValueError(f"Unsupported data_type: {data_type}") + + link_ids: list[str] = [] + demand_ids: list[str] = [] + unsupported_ids: list[str] = [] + for sensor_id in sensor_ids: + scada_type = sensor_metadata[sensor_id]["scada_type"] + if scada_type in {"pipe_flow", "flow"}: + link_ids.append(sensor_id) + elif scada_type == "demand": + demand_ids.append(sensor_id) + else: + unsupported_ids.append(f"{sensor_id}({scada_type})") + if unsupported_ids: + preview = ", ".join(unsupported_ids[:10]) + raise ValueError(f"flow 模拟数据暂不支持以下 SCADA 类型: {preview}") + + if link_ids: + result.update( + _query_simulation_values( + network=network, + element_ids=link_ids, + element_type="link", + field="flow", + start_dt=start_dt, + end_dt=end_dt, + simulation_source=simulation_source, + simulation_scheme_name=simulation_scheme_name, + simulation_scheme_type=simulation_scheme_type, + ) + ) + if demand_ids: + result.update( + _query_simulation_values( + network=network, + element_ids=demand_ids, + element_type="node", + field="actual_demand", + start_dt=start_dt, + end_dt=end_dt, + simulation_source=simulation_source, + simulation_scheme_name=simulation_scheme_name, + simulation_scheme_type=simulation_scheme_type, + ) + ) + return result + + +def _query_simulation_values( + *, + network: str, + element_ids: list[str], + element_type: str, + field: str, + start_dt: datetime, + end_dt: datetime, + simulation_source: str, + simulation_scheme_name: str | None, + simulation_scheme_type: str, +) -> dict[str, list[dict[str, Any]]]: + if not element_ids: + return {} + if simulation_source == "scheme": + if not simulation_scheme_name: + raise ValueError("读取方案模拟数据时必须提供 simulation_scheme_name。") + return InternalQueries.query_scheme_simulation_by_ids_timerange( + db_name=network, + scheme_type=simulation_scheme_type, + scheme_name=simulation_scheme_name, + element_ids=element_ids, + start_time=start_dt.isoformat(), + end_time=end_dt.isoformat(), + element_type=element_type, + field=field, + ) + if simulation_source == "realtime": + return InternalQueries.query_realtime_simulation_by_ids_timerange( + db_name=network, + element_ids=element_ids, + start_time=start_dt.isoformat(), + end_time=end_dt.isoformat(), + element_type=element_type, + field=field, + ) + raise ValueError(f"Unsupported simulation_source: {simulation_source}") + + +def _build_sensor_metadata(network: str, data_type: str) -> dict[str, dict[str, str]]: + metadata: dict[str, dict[str, str]] = {} + for item in get_all_scada_info(network): + scada_type = str(item.get("type", "")).lower() + if data_type == "pressure": + if scada_type != "pressure": + continue + elif data_type == "flow": + if scada_type not in FLOW_SCADA_TYPES: + continue + else: + raise ValueError(f"Unsupported data_type: {data_type}") + element_id = item.get("associated_element_id") + query_id = item.get("api_query_id") + if ( + isinstance(element_id, str) + and element_id + and isinstance(query_id, str) + and query_id + ): + metadata[element_id] = {"query_id": query_id, "scada_type": scada_type} + return metadata + + +def _build_scada_mapping(network: str, data_type: str) -> dict[str, str]: + metadata = _build_sensor_metadata(network=network, data_type=data_type) + return {element_id: item["query_id"] for element_id, item in metadata.items()} + + +def _normalize_data_source( + data_source: str | None, simulation_scheme_name: str | None = None +) -> str: + normalized = str(data_source or "").strip().lower() + if not normalized: + return "simulation" if simulation_scheme_name else "monitoring" + if normalized not in SIMULATION_DATA_SOURCES: + allowed_sources = ", ".join(sorted(SIMULATION_DATA_SOURCES)) + raise ValueError( + f"Unsupported data_source: {data_source}. Allowed: {allowed_sources}" + ) + return normalized + + +def _get_sensor_nodes(network: str, data_type: str) -> list[str]: + mapping = _build_scada_mapping(network=network, data_type=data_type) + sensor_ids = sorted(mapping.keys()) + if not sensor_ids: + type_name = "压力" if data_type == "pressure" else "流量" + raise ValueError(f"未找到{type_name}传感器对应节点(scada_info.type)。") + return sensor_ids + + +def _dedupe_ids(ids: list[str] | None) -> list[str]: + if ids is None: + return [] + return list(dict.fromkeys([str(item) for item in ids if item])) + + +def _to_datetime(value: datetime | str) -> datetime: + if isinstance(value, datetime): + return value + return datetime.fromisoformat(value) + + +def _prepare_burst_inp(network: str) -> str: + project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) + db_inp_dir = os.path.join(project_root, "db_inp") + os.makedirs(db_inp_dir, exist_ok=True) + inp_path = os.path.join(db_inp_dir, f"{network}.burst.inp") + if os.path.isfile(inp_path) and os.path.getsize(inp_path) > 0: + return inp_path + dump_inp(network, inp_path, "2") + if not os.path.isfile(inp_path) or os.path.getsize(inp_path) <= 0: + raise ValueError(f"爆管定位 INP 文件无效: {inp_path}") + return inp_path diff --git a/globals.py b/app/services/globals.py similarity index 100% rename from globals.py rename to app/services/globals.py diff --git a/app/services/leakage_identifier.py b/app/services/leakage_identifier.py new file mode 100644 index 0000000..e90cb24 --- /dev/null +++ b/app/services/leakage_identifier.py @@ -0,0 +1,527 @@ +import math +import os +from collections import deque +from datetime import datetime +from typing import Any + +import numpy as np +import pandas as pd +import wntr + +from app.algorithms.leakage.identifier import LeakageIdentifier +from app.infra.db.timescaledb.internal_queries import InternalQueries +from app.services.scheme_management import ( + query_leakage_identify_scheme_detail, + query_leakage_identify_schemes, + scheme_name_exists, + store_leakage_identify_result, + store_scheme_info, +) +from app.services.tjnetwork import ( + dump_inp, + get_all_scada_info, + get_network_link_nodes, + get_network_node_coords, +) + +DEFAULT_N_WORKERS = max(1, min((os.cpu_count() or 1) - 1, 4)) + + +def run_leakage_identification( + network: str, + username: str, + observed_pressure_data: ( + str | pd.DataFrame | dict[str, list[Any]] | list[dict[str, Any]] | None + ) = None, + start_time: float = 0, + duration: float = 24, + timestep: float = 5, + q_sum: float = 0.2, + q_sum_unit: str = "m3/s", + output_dir: str = "db_inp", + pop_size: int = 50, + max_gen: int = 100, + n_workers: int = DEFAULT_N_WORKERS, + output_flow_unit: str = "m3/s", + dma_count: int | None = None, + scada_start: datetime | str | None = None, + scada_end: datetime | str | None = None, + sensor_nodes: list[str] | None = None, + scheme_name: str | None = None, +) -> dict[str, Any]: + os.makedirs(output_dir, exist_ok=True) + inp_path = _prepare_leakage_inp(network) + + selected_sensor_nodes = ( + list(dict.fromkeys([node for node in (sensor_nodes or []) if node])) + if sensor_nodes + else _get_pressure_sensor_nodes(network) + ) + if not selected_sensor_nodes: + raise ValueError("未提供有效传感器节点,且系统未识别到可用压力传感器。") + + area_map, areas, node_coords = _build_area_map_by_topology( + network, selected_sensor_nodes, dma_count + ) + + observed_source = "request_payload" + if scada_start is not None or scada_end is not None: + observed_df = _build_observed_pressure_from_scada( + network=network, + sensor_nodes=selected_sensor_nodes, + scada_start=scada_start, + scada_end=scada_end, + ) + observed_source = "backend_timerange" + else: + if observed_pressure_data is None: + raise ValueError( + "未提供 observed_pressure_data,且未提供 scada_start/scada_end。" + ) + observed_df = observed_pressure_data + + q_sum_m3s = LeakageIdentifier._flow_to_m3s(q_sum, q_sum_unit) + identifier = LeakageIdentifier( + inp_path=inp_path, + sensor_nodes=selected_sensor_nodes, + area_map=area_map, + start_time=start_time, + duration=duration, + timestep=timestep, + q_sum=q_sum_m3s, + ) + result_df = identifier.run_identification( + observed_pressure_data=observed_df, + output_dir=output_dir, + pop_size=pop_size, + max_gen=max_gen, + n_workers=n_workers, + output_flow_unit=output_flow_unit, + save_result=False, + ) + rows = result_df.to_dict(orient="records") + # node_visual_payload = _build_node_visual_payload(area_map, node_coords, rows) + # drawing_payload = _build_drawing_payload(node_visual_payload) + payload = { + "result_path": result_df.attrs.get("result_path"), + "sensor_nodes": selected_sensor_nodes, + "observed_source": observed_source, + "area_count": len(set(area_map.values())), + "node_area_map": area_map, + "areas": areas, + # "node_visual_payload": node_visual_payload, + # "drawing_payload": drawing_payload, + "rows": rows, + } + if scheme_name: + if scheme_name_exists(network, scheme_name): + raise ValueError(f"方案名称已存在: {scheme_name}") + scheme_start_time = ( + _to_datetime(scada_start).isoformat() + if scada_start is not None + else datetime.now().isoformat() + ) + scheme_detail = { + "network": network, + "dma_count": dma_count, + "sensor_nodes": selected_sensor_nodes, + "scada_start": ( + _to_datetime(scada_start).isoformat() + if scada_start is not None + else None + ), + "scada_end": ( + _to_datetime(scada_end).isoformat() if scada_end is not None else None + ), + "algorithm_params": { + "start_time": start_time, + "duration": duration, + "timestep": timestep, + "q_sum": q_sum, + "q_sum_unit": q_sum_unit, + "output_flow_unit": output_flow_unit, + "pop_size": pop_size, + "max_gen": max_gen, + "n_workers": n_workers, + }, + "result_summary": { + "area_count": len(set(area_map.values())), + "max_leakage": max( + (float(row.get("LeakageFlow_m3_per_s", 0.0)) for row in rows), + default=0.0, + ), + }, + } + store_scheme_info( + name=network, + scheme_name=scheme_name, + scheme_type="dma_leak_identification", + username=username, + scheme_start_time=scheme_start_time, + scheme_detail=scheme_detail, + ) + store_leakage_identify_result( + name=network, + scheme_name=scheme_name, + network=network, + sensor_nodes=selected_sensor_nodes, + result_rows=rows, + node_area_map=area_map, + areas=areas, + drawing_payload={}, + ) + payload["scheme_name"] = scheme_name + return payload + + +def list_leakage_identify_schemes( + network: str, query_date: datetime | str | None = None +) -> list[dict[str, Any]]: + parsed_date = _to_datetime(query_date).date() if query_date is not None else None + return query_leakage_identify_schemes( + name=network, network=network, query_date=parsed_date + ) + + +def get_leakage_identify_scheme_detail( + network: str, scheme_name: str +) -> dict[str, Any]: + result = query_leakage_identify_scheme_detail(network, scheme_name) + if not result: + raise ValueError(f"未找到漏损识别方案: {scheme_name}") + return result + + +def _get_pressure_sensor_nodes(network: str) -> list[str]: + scada_info = get_all_scada_info(network) + sensor_nodes: list[str] = [] + for item in scada_info: + scada_type = str(item.get("type", "")).lower() + if scada_type != "pressure": + continue + node_id = item.get("associated_element_id") + if isinstance(node_id, str) and node_id: + sensor_nodes.append(node_id) + sensor_nodes = list(dict.fromkeys(sensor_nodes)) + if not sensor_nodes: + raise ValueError("未找到压力传感器对应节点(scada_info.type=pressure)。") + return sensor_nodes + + +def _build_area_map_by_topology( + network: str, sensor_nodes: list[str], dma_count: int | None +) -> tuple[dict[str, str], list[dict[str, Any]], dict[str, dict[str, float]]]: + node_coords = get_network_node_coords(network) + all_nodes = list(node_coords.keys()) + if not all_nodes: + raise ValueError("管网中未获取到可分区节点。") + + available_sensors = [node for node in sensor_nodes if node in node_coords] + if not available_sensors: + raise ValueError("无可用压力传感器,无法生成虚拟分区。") + area_count = _resolve_dma_count(dma_count, available_sensors, all_nodes) + sensor_area_map = _cluster_sensors_to_areas( + available_sensors, node_coords, area_count + ) + adjacency = _build_adjacency(network, all_nodes) + distance_by_sensor = { + sensor: _bfs_distances(adjacency, sensor) for sensor in available_sensors + } + + assignment_count = {sensor: 0 for sensor in available_sensors} + area_map: dict[str, str] = {} + for node_id in sorted(all_nodes): + sensor = _choose_sensor_for_node( + node_id=node_id, + sensors=available_sensors, + node_coords=node_coords, + distance_by_sensor=distance_by_sensor, + assignment_count=assignment_count, + ) + assignment_count[sensor] += 1 + area_map[node_id] = sensor_area_map[sensor] + + if not area_map: + raise ValueError("虚拟分区结果为空,无法生成节点区域映射。") + + areas = _build_area_meta(area_map, sensor_area_map) + return area_map, areas, node_coords + + +def _resolve_dma_count( + dma_count: int | None, sensor_nodes: list[str], all_nodes: list[str] +) -> int: + if dma_count is None: + return min(len(sensor_nodes), len(all_nodes)) + if dma_count <= 0: + raise ValueError("dma_count 必须大于 0。") + if dma_count > len(all_nodes): + raise ValueError("dma_count 不能大于可分区节点数量。") + if dma_count > len(sensor_nodes): + raise ValueError("dma_count 不能大于可用传感器数量。") + return dma_count + + +def _cluster_sensors_to_areas( + sensor_nodes: list[str], node_coords: dict[str, dict[str, float]], area_count: int +) -> dict[str, str]: + if area_count >= len(sensor_nodes): + return {sensor: str(i + 1) for i, sensor in enumerate(sensor_nodes)} + + points = np.array( + [ + [float(node_coords[s]["x"]), float(node_coords[s]["y"])] + for s in sensor_nodes + ], + dtype=float, + ) + centers = points[:area_count].copy() + labels = np.zeros(points.shape[0], dtype=int) + for _ in range(20): + d2 = ((points[:, None, :] - centers[None, :, :]) ** 2).sum(axis=2) + new_labels = d2.argmin(axis=1) + if np.array_equal(labels, new_labels): + break + labels = new_labels + for i in range(area_count): + cluster_points = points[labels == i] + if cluster_points.size > 0: + centers[i] = cluster_points.mean(axis=0) + return { + sensor: str(int(labels[idx]) + 1) for idx, sensor in enumerate(sensor_nodes) + } + + +def _build_adjacency(network: str, all_nodes: list[str]) -> dict[str, set[str]]: + adjacency: dict[str, set[str]] = {node: set() for node in all_nodes} + for link in get_network_link_nodes(network): + parts = str(link).split(":") + if len(parts) < 4: + continue + node1, node2 = parts[-2], parts[-1] + if node1 in adjacency and node2 in adjacency: + adjacency[node1].add(node2) + adjacency[node2].add(node1) + return adjacency + + +def _bfs_distances(adjacency: dict[str, set[str]], start: str) -> dict[str, int]: + distances: dict[str, int] = {start: 0} + queue: deque[str] = deque([start]) + while queue: + node = queue.popleft() + for neighbor in adjacency.get(node, set()): + if neighbor in distances: + continue + distances[neighbor] = distances[node] + 1 + queue.append(neighbor) + return distances + + +def _choose_sensor_for_node( + node_id: str, + sensors: list[str], + node_coords: dict[str, dict[str, float]], + distance_by_sensor: dict[str, dict[str, int]], + assignment_count: dict[str, int], +) -> str: + min_distance = None + candidates: list[str] = [] + for sensor in sensors: + d = distance_by_sensor.get(sensor, {}).get(node_id) + if d is None: + continue + if min_distance is None or d < min_distance: + min_distance = d + candidates = [sensor] + elif d == min_distance: + candidates.append(sensor) + if not candidates: + node_coord = node_coords[node_id] + return min( + sensors, + key=lambda sensor: _euclidean_distance( + node_coord, node_coords.get(sensor, node_coord) + ), + ) + return min(candidates, key=lambda sensor: (assignment_count[sensor], sensor)) + + +def _euclidean_distance(a: dict[str, float], b: dict[str, float]) -> float: + return math.hypot(float(a["x"]) - float(b["x"]), float(a["y"]) - float(b["y"])) + + +def _build_area_meta( + area_map: dict[str, str], sensor_area_map: dict[str, str] +) -> list[dict[str, Any]]: + nodes_by_area: dict[str, list[str]] = {} + for node_id, area_id in area_map.items(): + nodes_by_area.setdefault(area_id, []).append(node_id) + + sensors_by_area: dict[str, list[str]] = {} + for sensor, area_id in sensor_area_map.items(): + sensors_by_area.setdefault(area_id, []).append(sensor) + + areas: list[dict[str, Any]] = [] + for area_id in sorted(nodes_by_area.keys(), key=lambda x: int(x)): + node_ids = sorted(nodes_by_area.get(area_id, [])) + sensor_nodes = sorted(sensors_by_area.get(area_id, [])) + areas.append( + { + "area_id": area_id, + "sensor_nodes": sensor_nodes, + "node_ids": node_ids, + "node_count": len(node_ids), + } + ) + return areas + + +def _build_area_node_map(area_map: dict[str, str]) -> dict[str, list[str]]: + area_node_map: dict[str, list[str]] = {} + for node_id, area_id in area_map.items(): + area_node_map.setdefault(area_id, []).append(node_id) + for area_id in list(area_node_map.keys()): + area_node_map[area_id] = sorted(area_node_map[area_id]) + return area_node_map + + +def _build_node_visual_payload( + area_map: dict[str, str], + node_coords: dict[str, dict[str, float]], + rows: list[dict[str, Any]], +) -> dict[str, Any]: + area_leakage_map = _build_area_leakage_map(rows) + max_leakage = max(area_leakage_map.values(), default=0.0) + features: list[dict[str, Any]] = [] + for node_id, area_id in area_map.items(): + coord = node_coords.get(node_id) + if not coord: + continue + leakage_flow = float(area_leakage_map.get(area_id, 0.0)) + leakage_level = _classify_leakage_level(leakage_flow, max_leakage) + features.append( + { + "type": "Feature", + "properties": { + "node_id": node_id, + "area_id": area_id, + "leakage_flow_m3_per_s": leakage_flow, + "leakage_level": leakage_level, + }, + "geometry": { + "type": "Point", + "coordinates": [float(coord["x"]), float(coord["y"])], + }, + } + ) + return {"type": "FeatureCollection", "features": features} + + +def _build_area_leakage_map(rows: list[dict[str, Any]]) -> dict[str, float]: + area_leakage_map: dict[str, float] = {} + for row in rows: + area_id = str(row.get("Area", "")).strip() + if not area_id: + continue + area_leakage_map[area_id] = float(row.get("LeakageFlow_m3_per_s", 0.0)) + return area_leakage_map + + +def _classify_leakage_level(leakage_flow: float, max_leakage: float) -> str: + if max_leakage <= 0: + return "normal" + ratio = leakage_flow / max_leakage + if ratio >= 0.75: + return "high" + if ratio >= 0.4: + return "medium" + if ratio > 0: + return "low" + return "normal" + + +def _build_drawing_payload(node_visual_payload: dict[str, Any]) -> dict[str, Any]: + return node_visual_payload + + +def _build_observed_pressure_from_scada( + network: str, + sensor_nodes: list[str], + scada_start: datetime | str | None, + scada_end: datetime | str | None, +) -> pd.DataFrame: + if scada_start is None or scada_end is None: + raise ValueError("使用后端 SCADA 查询时必须同时提供 scada_start 与 scada_end。") + + start_dt = _to_datetime(scada_start) + end_dt = _to_datetime(scada_end) + if start_dt >= end_dt: + raise ValueError("SCADA 时间窗非法:scada_start 必须早于 scada_end。") + + node_query_id: dict[str, str] = {} + for item in get_all_scada_info(network): + if str(item.get("type", "")).lower() != "pressure": + continue + node_id = item.get("associated_element_id") + query_id = item.get("api_query_id") + if ( + isinstance(node_id, str) + and node_id + and isinstance(query_id, str) + and query_id + ): + node_query_id[node_id] = query_id + + query_ids = [node_query_id[node] for node in sensor_nodes if node in node_query_id] + if not query_ids: + raise ValueError("未找到可用于压力观测的 SCADA api_query_id。") + + scada_data = InternalQueries.query_scada_by_ids_timerange( + db_name=network, + device_ids=query_ids, + start_time=start_dt.isoformat(), + end_time=end_dt.isoformat(), + ) + + available_lengths = [ + len(scada_data.get(query_id, [])) + for query_id in query_ids + if len(scada_data.get(query_id, [])) > 0 + ] + if not available_lengths: + raise ValueError("指定时间窗内未查询到压力 SCADA 数据。") + min_len = min(available_lengths) + + obs_df = pd.DataFrame() + for node_id in sensor_nodes: + query_id = node_query_id.get(node_id) + if not query_id: + continue + records = scada_data.get(query_id, [])[:min_len] + if len(records) < min_len: + continue + obs_df[node_id] = [float(item["value"]) for item in records] + + if obs_df.empty: + raise ValueError("SCADA 压力数据无法构建观测矩阵。") + return obs_df + + +def _to_datetime(value: datetime | str) -> datetime: + if isinstance(value, datetime): + return value + return datetime.fromisoformat(value) + + +def _prepare_leakage_inp(network: str) -> str: + project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) + db_inp_dir = os.path.join(project_root, "db_inp") + os.makedirs(db_inp_dir, exist_ok=True) + inp_path = os.path.join(db_inp_dir, f"{network}.leakage.inp") + if os.path.isfile(inp_path) and os.path.getsize(inp_path) > 0: + return inp_path + dump_inp(network, inp_path, "2") + if not os.path.isfile(inp_path) or os.path.getsize(inp_path) <= 0: + raise ValueError(f"漏损识别 INP 文件无效: {inp_path}") + return inp_path diff --git a/app/services/network_import.py b/app/services/network_import.py new file mode 100644 index 0000000..3c8e5df --- /dev/null +++ b/app/services/network_import.py @@ -0,0 +1,197 @@ +import csv +import os + +import chardet +import psycopg +from psycopg import sql + +import app.services.project_info as project_info +from app.core.config import get_pgconn_string +from app.services.tjnetwork import read_inp + + +############################################################ +# network_update 10 +############################################################ + + +def network_update(file_path: str) -> None: + """ + 更新pg数据库中的inp文件 + :param file_path: inp文件 + :return: + """ + read_inp("szh", file_path) + + csv_path = "./history_pattern_flow.csv" + + # # 检查文件是否存在 + # if os.path.exists(csv_path): + # print(f"history_patterns_flows文件存在,开始处理...") + # + # # 读取 CSV 文件 + # df = pd.read_csv(csv_path) + # + # # 连接到 PostgreSQL 数据库(这里是数据库 "bb") + # with psycopg.connect("dbname=bb host=127.0.0.1") as conn: + # with conn.cursor() as cur: + # for index, row in df.iterrows(): + # # 直接将数据插入,不进行唯一性检查 + # insert_sql = sql.SQL(""" + # INSERT INTO history_patterns_flows (id, factor, flow) + # VALUES (%s, %s, %s); + # """) + # # 将数据插入数据库 + # cur.execute(insert_sql, (row['id'], row['factor'], row['flow'])) + # conn.commit() + # print("数据成功导入到 'history_patterns_flows' 表格。") + # else: + # print(f"history_patterns_flows文件不存在。") + # 检查文件是否存在 + if os.path.exists(csv_path): + print(f"history_patterns_flows文件存在,开始处理...") + + # 连接到 PostgreSQL 数据库(这里是数据库 "bb") + with psycopg.connect(f"dbname={project_info.name} host=127.0.0.1") as conn: + with conn.cursor() as cur: + with open(csv_path, newline="", encoding="utf-8-sig") as csvfile: + reader = csv.DictReader(csvfile) + for row in reader: + # 直接将数据插入,不进行唯一性检查 + insert_sql = sql.SQL( + """ + INSERT INTO history_patterns_flows (id, factor, flow) + VALUES (%s, %s, %s); + """ + ) + # 将数据插入数据库 + cur.execute(insert_sql, (row["id"], row["factor"], row["flow"])) + conn.commit() + print("数据成功导入到 'history_patterns_flows' 表格。") + else: + print(f"history_patterns_flows文件不存在。") + + +def submit_scada_info(name: str, coord_id: str) -> None: + """ + 将scada信息表导入pg数据库 + :param name: 项目名称(数据库名称) + :param coord_id: 坐标系的id,如4326,根据原始坐标信息输入 + :return: + """ + scada_info_path = "./scada_info.csv" + # 检查文件是否存在 + if os.path.exists(scada_info_path): + print(f"scada_info文件存在,开始处理...") + + # 自动检测文件编码 + with open(scada_info_path, "rb") as file: + raw_data = file.read() + detected = chardet.detect(raw_data) + file_encoding = detected["encoding"] + print(f"检测到的文件编码:{file_encoding}") + try: + # 动态替换数据库名称 + conn_string = get_pgconn_string(db_name=name) + + # 连接到 PostgreSQL 数据库(这里是数据库 "bb") + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + # 检查 scada_info 表是否为空 + cur.execute("SELECT COUNT(*) FROM scada_info;") + count = cur.fetchone()[0] + + if count > 0: + print("scada_info表中已有数据,正在清空记录...") + cur.execute("DELETE FROM scada_info;") + print("表记录已清空。") + + with open( + scada_info_path, newline="", encoding=file_encoding + ) as csvfile: + reader = csv.DictReader(csvfile) + for row in reader: + # 将CSV单元格值为空的字段转换为 None + cleaned_row = { + key: (value if value.strip() else None) + for key, value in row.items() + } + + # 处理 associated_source_outflow_id 列动态变化 + associated_columns = [ + f"associated_source_outflow_id{i}" for i in range(1, 21) + ] + associated_values = [ + ( + cleaned_row.get(col).strip() + if cleaned_row.get(col) + and cleaned_row.get(col).strip() + else None + ) + for col in associated_columns + ] + + # 将 X_coor 和 Y_coor 转换为 geometry 类型 + x_coor = ( + float(cleaned_row["X_coor"]) + if cleaned_row["X_coor"] + else None + ) + y_coor = ( + float(cleaned_row["Y_coor"]) + if cleaned_row["Y_coor"] + else None + ) + coord = ( + f"SRID={coord_id};POINT({x_coor} {y_coor})" + if x_coor and y_coor + else None + ) + + # 准备插入 SQL 语句 + insert_sql = sql.SQL( + """ + INSERT INTO scada_info ( + id, type, associated_element_id, associated_pattern, + associated_pipe_flow_id, {associated_columns}, + API_query_id, transmission_mode, transmission_frequency, + reliability, X_coor, Y_coor, coord + ) + VALUES ( + %s, %s, %s, %s, %s, {associated_placeholders}, + %s, %s, %s, %s, %s, %s, %s + ); + """ + ).format( + associated_columns=sql.SQL(", ").join( + sql.Identifier(col) for col in associated_columns + ), + associated_placeholders=sql.SQL(", ").join( + sql.Placeholder() for _ in associated_columns + ), + ) + # 将数据插入数据库 + cur.execute( + insert_sql, + ( + cleaned_row["id"], + cleaned_row["type"], + cleaned_row["associated_element_id"], + cleaned_row.get("associated_pattern"), + cleaned_row.get("associated_pipe_flow_id"), + *associated_values, + cleaned_row.get("API_query_id"), + cleaned_row["transmission_mode"], + cleaned_row["transmission_frequency"], + cleaned_row["reliability"], + x_coor, + y_coor, + coord, + ), + ) + conn.commit() + print("数据成功导入到 'scada_info' 表格。") + except Exception as e: + print(f"导入时出错:{e}") + else: + print(f"scada_info文件不存在。") diff --git a/app/services/project_info.py b/app/services/project_info.py new file mode 100644 index 0000000..0a38481 --- /dev/null +++ b/app/services/project_info.py @@ -0,0 +1,4 @@ +import os + +# 从环境变量 NETWORK_NAME 读取 +name = os.getenv("NETWORK_NAME") diff --git a/app/services/scheme_management.py b/app/services/scheme_management.py new file mode 100644 index 0000000..a86a9bd --- /dev/null +++ b/app/services/scheme_management.py @@ -0,0 +1,576 @@ +import ast +import json +from datetime import date + +import geopandas as gpd +import pandas as pd +import psycopg +from sqlalchemy import create_engine + +from app.core.config import get_pgconn_string + + +# 2025/03/23 +def create_user(name: str, username: str, password: str): + """ + 创建用户 + :param name: 数据库名称 + :param username: 用户名 + :param password: 密码 + :return: + """ + try: + # 动态替换数据库名称 + conn_string = get_pgconn_string(db_name=name) + # 连接到 PostgreSQL 数据库(这里是数据库 "bb") + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + cur.execute( + "INSERT INTO users (username, password) VALUES (%s, %s)", + (username, password), + ) + # 提交事务 + conn.commit() + print("新用户创建成功!") + except Exception as e: + print(f"创建用户出错:{e}") + + +# 2025/03/23 +def delete_user(name: str, username: str): + """ + 删除用户 + :param name: 数据库名称 + :param username: 用户名 + :return: + """ + try: + # 动态替换数据库名称 + conn_string = get_pgconn_string(db_name=name) + # 连接到 PostgreSQL 数据库(这里是数据库 "bb") + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + cur.execute("DELETE FROM users WHERE username = %s", (username,)) + conn.commit() + print(f"用户 {username} 删除成功!") + except Exception as e: + print(f"删除用户出错:{e}") + + +# 2025/03/23 +def scheme_name_exists(name: str, scheme_name: str) -> bool: + """ + 判断传入的 scheme_name 是否已存在于 scheme_list 表中,用于输入框判断 + :param name: 数据库名称 + :param scheme_name: 需要判断的方案名称 + :return: 如果存在返回 True,否则返回 False + """ + try: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + cur.execute( + "SELECT COUNT(*) FROM scheme_list WHERE scheme_name = %s", + (scheme_name,), + ) + result = cur.fetchone() + if result is not None and result[0] > 0: + return True + else: + return False + except Exception as e: + print(f"查询 scheme_name 时出错:{e}") + return False + + +# 2025/03/23 +def store_scheme_info( + name: str, + scheme_name: str, + scheme_type: str, + username: str, + scheme_start_time: str, + scheme_detail: dict, +): + """ + 将一条方案记录插入 scheme_list 表中 + :param name: 数据库名称 + :param scheme_name: 方案名称 + :param scheme_type: 方案类型 + :param username: 用户名(需在 users 表中已存在) + :param scheme_start_time: 方案起始时间(字符串) + :param scheme_detail: 方案详情(字典,会转换为 JSON) + :return: + """ + try: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + sql = """ + INSERT INTO scheme_list (scheme_name, scheme_type, username, scheme_start_time, scheme_detail) + VALUES (%s, %s, %s, %s, %s) + """ + # 将字典转换为 JSON 字符串 + scheme_detail_json = json.dumps(scheme_detail) + cur.execute( + sql, + ( + scheme_name, + scheme_type, + username, + scheme_start_time, + scheme_detail_json, + ), + ) + conn.commit() + print("方案信息存储成功!") + except Exception as e: + print(f"存储方案信息时出错:{e}") + + +# 2025/03/23 +def delete_scheme_info(name: str, scheme_name: str) -> None: + """ + 从 scheme_list 表中删除指定的方案 + :param name: 数据库名称 + :param scheme_name: 要删除的方案名称 + """ + try: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + # 使用参数化查询删除方案记录 + cur.execute( + "DELETE FROM scheme_list WHERE scheme_name = %s", (scheme_name,) + ) + conn.commit() + print(f"方案 {scheme_name} 删除成功!") + except Exception as e: + print(f"删除方案时出错:{e}") + + +# 2025/03/23 +def query_scheme_list(name: str) -> list: + """ + 查询pg数据库中的scheme_list,按照 create_time 降序排列,离现在时间最近的记录排在最前面 + :param name: 项目名称(数据库名称) + :return: 返回查询结果的所有行 + """ + try: + # 动态替换数据库名称 + conn_string = get_pgconn_string(db_name=name) + # 连接到 PostgreSQL 数据库(这里是数据库 "bb") + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + # 按 create_time 降序排列 + cur.execute("SELECT * FROM scheme_list ORDER BY create_time DESC") + rows = cur.fetchall() + return rows + + except Exception as e: + print(f"查询错误:{e}") + + +def store_leakage_identify_result( + name: str, + scheme_name: str, + network: str, + sensor_nodes: list[str], + result_rows: list[dict], + node_area_map: dict[str, str], + areas: list[dict], + drawing_payload: dict | None = None, + run_status: str = "completed", + error_message: str | None = None, +) -> None: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + cur.execute( + """ + INSERT INTO public.leakage_identify_result + ( + scheme_name, network, run_status, error_message, + sensor_nodes, result_rows, node_area_map, areas, drawing_payload + ) + VALUES (%s, %s, %s, %s, %s::jsonb, %s::jsonb, %s::jsonb, %s::jsonb, %s::jsonb) + ON CONFLICT (scheme_name) + DO UPDATE SET + network = EXCLUDED.network, + run_status = EXCLUDED.run_status, + error_message = EXCLUDED.error_message, + sensor_nodes = EXCLUDED.sensor_nodes, + result_rows = EXCLUDED.result_rows, + node_area_map = EXCLUDED.node_area_map, + areas = EXCLUDED.areas, + drawing_payload = EXCLUDED.drawing_payload, + created_at = NOW(); + """, + ( + scheme_name, + network, + run_status, + error_message, + json.dumps(sensor_nodes), + json.dumps(result_rows), + json.dumps(node_area_map), + json.dumps(areas), + json.dumps(drawing_payload or {}), + ), + ) + conn.commit() + + +def query_leakage_identify_schemes( + name: str, + network: str, + scheme_type: str = "dma_leak_identification", + query_date: date | None = None, +) -> list[dict]: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + if query_date is None: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_type = %s + ORDER BY create_time DESC + """, + (scheme_type,), + ) + else: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_type = %s AND DATE(create_time) = %s + ORDER BY create_time DESC + """, + (scheme_type, query_date), + ) + rows = cur.fetchall() + result = [] + for row in rows: + detail = row[6] if isinstance(row[6], dict) else {} + if network and detail.get("network") not in (None, network): + continue + result.append( + { + "scheme_id": row[0], + "scheme_name": row[1], + "scheme_type": row[2], + "username": row[3], + "create_time": row[4], + "scheme_start_time": row[5], + "scheme_detail": detail, + } + ) + return result + + +def query_leakage_identify_scheme_detail(name: str, scheme_name: str) -> dict: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_name = %s + LIMIT 1 + """, + (scheme_name,), + ) + base_row = cur.fetchone() + if base_row is None: + return {} + cur.execute( + """ + SELECT network, created_at, run_status, error_message, sensor_nodes, result_rows, node_area_map, areas, drawing_payload + FROM public.leakage_identify_result + WHERE scheme_name = %s + LIMIT 1 + """, + (scheme_name,), + ) + result_row = cur.fetchone() + if result_row is None: + return {} + return { + "scheme_id": base_row[0], + "scheme_name": base_row[1], + "scheme_type": base_row[2], + "username": base_row[3], + "create_time": base_row[4], + "scheme_start_time": base_row[5], + "scheme_detail": base_row[6] if isinstance(base_row[6], dict) else {}, + "network": result_row[0], + "result_created_at": result_row[1], + "run_status": result_row[2], + "error_message": result_row[3], + "sensor_nodes": result_row[4] if isinstance(result_row[4], list) else [], + "rows": result_row[5] if isinstance(result_row[5], list) else [], + "node_area_map": result_row[6] if isinstance(result_row[6], dict) else {}, + "areas": result_row[7] if isinstance(result_row[7], list) else [], + "drawing_payload": ( + result_row[8] + if isinstance(result_row[8], dict) + else {"type": "FeatureCollection", "features": []} + ), + } + + +def query_burst_location_schemes( + name: str, + network: str, + scheme_type: str = "burst_location", + query_date: date | None = None, +) -> list[dict]: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + if query_date is None: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_type = %s + ORDER BY create_time DESC + """, + (scheme_type,), + ) + else: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_type = %s AND DATE(create_time) = %s + ORDER BY create_time DESC + """, + (scheme_type, query_date), + ) + rows = cur.fetchall() + result = [] + for row in rows: + detail = row[6] if isinstance(row[6], dict) else {} + if network and detail.get("network") not in (None, network): + continue + result.append( + { + "scheme_id": row[0], + "scheme_name": row[1], + "scheme_type": row[2], + "username": row[3], + "create_time": row[4], + "scheme_start_time": row[5], + "scheme_detail": detail, + } + ) + return result + + +def query_burst_location_scheme_detail(name: str, scheme_name: str) -> dict: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_name = %s + LIMIT 1 + """, + (scheme_name,), + ) + base_row = cur.fetchone() + if base_row is None: + return {} + detail = base_row[6] if isinstance(base_row[6], dict) else {} + return { + "scheme_id": base_row[0], + "scheme_name": base_row[1], + "scheme_type": base_row[2], + "username": base_row[3], + "create_time": base_row[4], + "scheme_start_time": base_row[5], + "scheme_detail": detail, + "network": detail.get("network"), + "result_payload": detail.get("result_payload", {}), + } + + +def query_burst_detection_schemes( + name: str, + network: str, + scheme_type: str = "burst_detection", + query_date: date | None = None, +) -> list[dict]: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + if query_date is None: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_type = %s + ORDER BY create_time DESC + """, + (scheme_type,), + ) + else: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_type = %s AND DATE(create_time) = %s + ORDER BY create_time DESC + """, + (scheme_type, query_date), + ) + rows = cur.fetchall() + result = [] + for row in rows: + detail = row[6] if isinstance(row[6], dict) else {} + if network and detail.get("network") not in (None, network): + continue + result.append( + { + "scheme_id": row[0], + "scheme_name": row[1], + "scheme_type": row[2], + "username": row[3], + "create_time": row[4], + "scheme_start_time": row[5], + "scheme_detail": detail, + } + ) + return result + + +def query_burst_detection_scheme_detail(name: str, scheme_name: str) -> dict: + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + cur.execute( + """ + SELECT scheme_id, scheme_name, scheme_type, username, create_time, scheme_start_time, scheme_detail + FROM public.scheme_list + WHERE scheme_name = %s + LIMIT 1 + """, + (scheme_name,), + ) + base_row = cur.fetchone() + if base_row is None: + return {} + detail = base_row[6] if isinstance(base_row[6], dict) else {} + return { + "scheme_id": base_row[0], + "scheme_name": base_row[1], + "scheme_type": base_row[2], + "username": base_row[3], + "create_time": base_row[4], + "scheme_start_time": base_row[5], + "scheme_detail": detail, + "network": detail.get("network"), + "result_payload": detail.get("result_payload", {}), + } + + +# 2025/03/23 +def upload_shp_to_pg(name: str, table_name: str, role: str, shp_file_path: str): + """ + 将 Shapefile 文件上传到 PostgreSQL 数据库 + :param name: 项目名称(数据库名称) + :param table_name: 创建表的名字 + :param role: 数据库角色名,位于c盘user中查看 + :param shp_file_path: shp文件的路径 + :return: + """ + try: + # 动态连接到指定的数据库 + conn_string = get_pgconn_string(db_name=name) + with psycopg.connect(conn_string) as conn: + # 读取 Shapefile 文件 + gdf = gpd.read_file(shp_file_path) + + # 检查投影坐标系(CRS),并确保是 EPSG:4326 + if gdf.crs.to_string() != "EPSG:4490": + gdf = gdf.to_crs(epsg=4490) + + # 使用 GeoDataFrame 的 .to_postgis 方法将数据写入 PostgreSQL + # 需要在数据库中提前安装 PostGIS 扩展 + engine = create_engine(f"postgresql+psycopg2://{role}:@127.0.0.1/{name}") + gdf.to_postgis( + table_name, engine, if_exists="replace", index=True, index_label="id" + ) + + print( + f"Shapefile 文件成功上传到 PostgreSQL 数据库 '{name}' 的表 '{table_name}'." + ) + + except Exception as e: + print(f"上传 Shapefile 到 PostgreSQL 时出错:{e}") + + +def submit_risk_probability_result(name: str, result_file_path: str) -> None: + """ + 将管网风险评估结果导入pg数据库 + :param name: 项目名称(数据库名称) + :param result_file_path: 结果文件路径 + :return: + """ + # 自动检测文件编码 + # with open({result_file_path}, 'rb') as file: + # raw_data = file.read() + # detected = chardet.detect(raw_data) + # file_encoding = detected['encoding'] + # print(f"检测到的文件编码:{file_encoding}") + + try: + # 动态替换数据库名称 + conn_string = get_pgconn_string(db_name=name) + + # 连接到 PostgreSQL 数据库 + with psycopg.connect(conn_string) as conn: + with conn.cursor() as cur: + # 检查 scada_info 表是否为空 + cur.execute("SELECT COUNT(*) FROM pipe_risk_probability;") + count = cur.fetchone()[0] + + if count > 0: + print("pipe_risk_probability表中已有数据,正在清空记录...") + cur.execute("DELETE FROM pipe_risk_probability;") + print("表记录已清空。") + + # 读取Excel并转换x/y列为列表 + df = pd.read_excel(result_file_path, sheet_name="Sheet1") + df["x"] = df["x"].apply(ast.literal_eval) + df["y"] = df["y"].apply(ast.literal_eval) + + # 批量插入数据 + for index, row in df.iterrows(): + insert_query = """ + INSERT INTO pipe_risk_probability + (pipeID, pipeage, risk_probability_now, x, y) + VALUES (%s, %s, %s, %s, %s) + """ + cur.execute( + insert_query, + ( + row["pipeID"], + row["pipeage"], + row["risk_probability_now"], + row["x"], # 直接传递列表 + row["y"], # 同上 + ), + ) + + conn.commit() + print("风险评估结果导入成功") + + except Exception as e: + print(f"导入时出错:{e}") diff --git a/simulation.py b/app/services/simulation.py similarity index 59% rename from simulation.py rename to app/services/simulation.py index 089b20f..4ac2779 100644 --- a/simulation.py +++ b/app/services/simulation.py @@ -1,8 +1,26 @@ import numpy as np -from tjnetwork import * -from api.s36_wda_cal import * +from app.services.tjnetwork import ( + ChangeSet, + get_demand, + get_option, + get_pattern, + get_pump, + get_reservoir, + get_status, + get_tank, + get_time, + open_project, + read_all, + run_project, + set_demand, + set_pattern, + set_status, + set_tank, + set_time, +) + # from get_real_status import * -from datetime import datetime,timedelta +from datetime import datetime, timedelta from math import modf import os import json @@ -10,18 +28,26 @@ import pytz import requests import time import shutil -from epanet.epanet import Output +from app.infra.epanet.epanet import Output from typing import Optional, Tuple -import influxdb_api +import app.infra.db.influxdb.api as influxdb_api import typing import psycopg import logging -import globals +import app.services.globals as globals import uuid -import project_info -from api.postgresql_info import get_pgconn_string +import app.services.project_info as project_info +from app.core.config import get_pgconn_string +from app.infra.db.timescaledb.internal_queries import ( + InternalQueries as TimescaleInternalQueries, +) +from app.infra.db.timescaledb.internal_queries import ( + InternalStorage as TimescaleInternalStorage, +) -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logging.basicConfig( + level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s" +) def query_corresponding_element_id_and_query_id(name: str) -> None: @@ -36,28 +62,30 @@ def query_corresponding_element_id_and_query_id(name: str) -> None: with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: # 查询 transmission_mode 为 'realtime' 的记录 - cur.execute(""" + cur.execute( + """ SELECT type, associated_element_id, api_query_id FROM scada_info WHERE transmission_mode = 'realtime'; - """) + """ + ) records = cur.fetchall() # 遍历查询结果,并根据 type 将数据存储到相应的字典中 for record in records: type_, associated_element_id, api_query_id = record - if type_ == 'reservoir_liquid_level': + if type_ == "reservoir_liquid_level": globals.reservoirs_id[associated_element_id] = api_query_id - elif type_ == 'tank_liquid_level': + elif type_ == "tank_liquid_level": globals.tanks_id[associated_element_id] = api_query_id - elif type_ == 'fixed_pump': + elif type_ == "fixed_pump": globals.fixed_pumps_id[associated_element_id] = api_query_id - elif type_ == 'variable_pump': + elif type_ == "variable_pump": globals.variable_pumps_id[associated_element_id] = api_query_id - elif type_ == 'pressure': + elif type_ == "pressure": globals.pressure_id[associated_element_id] = api_query_id - elif type_ == 'demand': + elif type_ == "demand": globals.demand_id[associated_element_id] = api_query_id - elif type_ == 'quality': + elif type_ == "quality": globals.quality_id[associated_element_id] = api_query_id else: # 如果遇到未定义的类型,可以选择记录日志或忽略 @@ -79,20 +107,26 @@ def query_corresponding_pattern_id_and_query_id(name: str) -> None: with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: # 查询 transmission_mode 为 'realtime' 且 type 为 'source_outflow' 或 'pipe_flow' 的记录 - cur.execute(""" + cur.execute( + """ SELECT type, associated_pattern, api_query_id FROM scada_info WHERE transmission_mode = 'realtime' AND type IN ('source_outflow', 'pipe_flow'); - """) + """ + ) records = cur.fetchall() # 遍历查询结果,并根据 type 将数据存储到相应的字典中 for record in records: type_, associated_pattern, api_query_id = record - if type_ == 'source_outflow': - globals.source_outflow_pattern_id[associated_pattern] = api_query_id - elif type_ == 'pipe_flow': - globals.realtime_pipe_flow_pattern_id[associated_pattern] = api_query_id + if type_ == "source_outflow": + globals.source_outflow_pattern_id[associated_pattern] = ( + api_query_id + ) + elif type_ == "pipe_flow": + globals.realtime_pipe_flow_pattern_id[associated_pattern] = ( + api_query_id + ) except psycopg.Error as e: print(f"数据库连接或查询出错: {e}") @@ -114,21 +148,32 @@ def query_non_realtime_region(name: str) -> dict: with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: # 执行查询,筛选出 transmission_mode 为 'non_realtime' 且 type 为 'pipe_flow' 的记录 - cur.execute(""" + cur.execute( + """ SELECT * FROM scada_info WHERE transmission_mode = 'non_realtime' AND type = 'pipe_flow'; - """) + """ + ) records = cur.fetchall() col_names = [desc.name for desc in cur.description] # 找出所有以 'associated_source_outflow_id' 开头的列 - source_outflow_cols = [col for col in col_names if col.startswith('associated_source_outflow_id')] - logging.info(f"Identified source_outflow columns: {source_outflow_cols}") + source_outflow_cols = [ + col + for col in col_names + if col.startswith("associated_source_outflow_id") + ] + logging.info( + f"Identified source_outflow columns: {source_outflow_cols}" + ) for record in records: # 提取所有以 'associated_source_outflow_id' 开头的列的值,排除 None - values = [record[col_names.index(col)] for col in source_outflow_cols if - record[col_names.index(col)] is not None] + values = [ + record[col_names.index(col)] + for col in source_outflow_cols + if record[col_names.index(col)] is not None + ] # 如果该记录有相关的值,则将其作为一个 region if values: # 将值排序以确保相同的组合顺序一致(如果顺序不重要) @@ -155,7 +200,11 @@ def query_non_realtime_region(name: str) -> dict: # 2025/01/18 -def query_non_realtime_region_patterns(name: str, source_outflow_region: dict, column_prefix: str = 'associated_source_outflow_id') -> dict: +def query_non_realtime_region_patterns( + name: str, + source_outflow_region: dict, + column_prefix: str = "associated_source_outflow_id", +) -> dict: """ 根据 source_outflow_region,对 scada_info 表中 transmission_mode 为 'non_realtime'的记录进行分组, 将匹配的记录的 associated_pattern 存入 non_realtime_region_patterns 字典中,同时把用 realtime pipe_flow修正的 non_realtime demand 去掉 @@ -164,33 +213,48 @@ def query_non_realtime_region_patterns(name: str, source_outflow_region: dict, c :param column_prefix: 需要提取的列的前缀 :return: 包含区域与对应 associated_pattern 的字典 """ - globals.non_realtime_region_patterns = {region: [] for region in globals.source_outflow_region.keys()} - region_tuple_to_key = {frozenset(ids): region for region, ids in globals.source_outflow_region.items()} + globals.non_realtime_region_patterns = { + region: [] for region in globals.source_outflow_region.keys() + } + region_tuple_to_key = { + frozenset(ids): region for region, ids in globals.source_outflow_region.items() + } conn_string = get_pgconn_string(db_name=name) try: with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: # 执行查询,筛选出 transmission_mode 为 'non_realtime' - cur.execute(""" + cur.execute( + """ SELECT * FROM scada_info WHERE transmission_mode = 'non_realtime' - """) + """ + ) records = cur.fetchall() col_names = [desc.name for desc in cur.description] # 找出所有以指定前缀开头的列 - source_outflow_cols = [col for col in col_names if col.startswith(column_prefix)] - logging.info(f"Identified source_outflow columns: {source_outflow_cols}") + source_outflow_cols = [ + col for col in col_names if col.startswith(column_prefix) + ] + logging.info( + f"Identified source_outflow columns: {source_outflow_cols}" + ) # 确保 'associated_pattern' 列存在 - if 'associated_pattern' not in col_names: - logging.error("'associated_pattern' column not found in scada_info table.") + if "associated_pattern" not in col_names: + logging.error( + "'associated_pattern' column not found in scada_info table." + ) return globals.non_realtime_region_patterns # 获取 'associated_pattern' 列的索引 - pattern_idx = col_names.index('associated_pattern') + pattern_idx = col_names.index("associated_pattern") for record in records: # 提取所有以 'associated_source_outflow_id' 开头的列的值,排除 None - values = [record[col_names.index(col)] for col in source_outflow_cols if - record[col_names.index(col)] is not None] + values = [ + record[col_names.index(col)] + for col in source_outflow_cols + if record[col_names.index(col)] is not None + ] if values: # 将值转换为 frozenset 以便与 region_tuple_to_key 进行匹配 region_frozenset = frozenset(values) @@ -200,22 +264,34 @@ def query_non_realtime_region_patterns(name: str, source_outflow_region: dict, c # 获取 'associated_pattern' 的值 associated_pattern = record[pattern_idx] if associated_pattern is not None: - globals.non_realtime_region_patterns[region_key].append(associated_pattern) + globals.non_realtime_region_patterns[region_key].append( + associated_pattern + ) logging.info("生成 regions_patterns 成功。") except psycopg.Error as e: logging.error(f"数据库连接或查询出错: {e}") except Exception as ex: logging.error(f"处理数据时出错: {ex}") # 获取pipe_flow_region_patterns中的所有区域 - exclude_regions = set(region for regions in globals.pipe_flow_region_patterns.values() for region in regions) + exclude_regions = set( + region + for regions in globals.pipe_flow_region_patterns.values() + for region in regions + ) # 从non_realtime_region_patterns中去除这些区域 for region_key, regions in globals.non_realtime_region_patterns.items(): - globals.non_realtime_region_patterns[region_key] = [region for region in regions if region not in exclude_regions] + globals.non_realtime_region_patterns[region_key] = [ + region for region in regions if region not in exclude_regions + ] return globals.non_realtime_region_patterns # 2025/01/18 -def query_realtime_region_pipe_flow_and_demand_id(name: str, source_outflow_region: dict, column_prefix: str = 'associated_source_outflow_id') -> dict: +def query_realtime_region_pipe_flow_and_demand_id( + name: str, + source_outflow_region: dict, + column_prefix: str = "associated_source_outflow_id", +) -> dict: """ 根据 source_outflow_region,对 scada_info 表中 transmission_mode 为 'realtime', 且 type 为 'pipe_flow' 或 ‘demand’ 的记录进行分组,将匹配的记录的 api_query_id 存入 realtime_region_pipe_flow_and_demand_id 字典中。 @@ -224,35 +300,50 @@ def query_realtime_region_pipe_flow_and_demand_id(name: str, source_outflow_regi :param column_prefix: 需要提取的列的前缀 :return: 包含区域与对应 api_query_id 的字典 """ - globals.realtime_region_pipe_flow_and_demand_id = {region: [] for region in globals.source_outflow_region.keys()} + globals.realtime_region_pipe_flow_and_demand_id = { + region: [] for region in globals.source_outflow_region.keys() + } # 创建一个映射,从 frozenset(ids) 到 region_key - region_tuple_to_key = {frozenset(ids): region for region, ids in globals.source_outflow_region.items()} + region_tuple_to_key = { + frozenset(ids): region for region, ids in globals.source_outflow_region.items() + } conn_string = get_pgconn_string(db_name=name) try: with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: # 执行查询,筛选出 transmission_mode 为 'realtime' 且 type 为 'pipe_flow' 或 'demand' 的记录 - cur.execute(""" + cur.execute( + """ SELECT * FROM scada_info WHERE transmission_mode = 'realtime' AND type IN ('pipe_flow', 'demand'); - """) + """ + ) records = cur.fetchall() col_names = [desc.name for desc in cur.description] # 找出所有以指定前缀开头的列 - source_outflow_cols = [col for col in col_names if col.startswith(column_prefix)] - logging.info(f"Identified source_outflow columns: {source_outflow_cols}") + source_outflow_cols = [ + col for col in col_names if col.startswith(column_prefix) + ] + logging.info( + f"Identified source_outflow columns: {source_outflow_cols}" + ) # 确保 'api_query_id' 列存在 - if 'api_query_id' not in col_names: - logging.error("'api_query_id' column not found in scada_info table.") + if "api_query_id" not in col_names: + logging.error( + "'api_query_id' column not found in scada_info table." + ) return globals.realtime_region_pipe_flow_and_demand_id # 获取 'api_query_id' 列的索引 - api_query_id_idx = col_names.index('api_query_id') + api_query_id_idx = col_names.index("api_query_id") for record in records: # 提取所有以 'associated_source_outflow_id' 开头的列的值,排除 None - values = [record[col_names.index(col)] for col in source_outflow_cols if - record[col_names.index(col)] is not None] + values = [ + record[col_names.index(col)] + for col in source_outflow_cols + if record[col_names.index(col)] is not None + ] if values: # 将值转换为 frozenset 以便与 region_tuple_to_key 进行匹配 region_frozenset = frozenset(values) @@ -262,7 +353,9 @@ def query_realtime_region_pipe_flow_and_demand_id(name: str, source_outflow_regi # 获取 'api_query_id' 的值 api_query_id = record[api_query_id_idx] if api_query_id is not None: - globals.realtime_region_pipe_flow_and_demand_id[region_key].append(api_query_id) + globals.realtime_region_pipe_flow_and_demand_id[ + region_key + ].append(api_query_id) logging.info("生成 realtime_region_pipe_flow_and_demand_id 成功。") except psycopg.Error as e: logging.error(f"数据库连接或查询出错: {e}") @@ -272,7 +365,9 @@ def query_realtime_region_pipe_flow_and_demand_id(name: str, source_outflow_regi # 2025/01/17 -def query_pipe_flow_region_patterns(name: str, column_prefix: str = 'associated_pipe_flow_id') -> dict: +def query_pipe_flow_region_patterns( + name: str, column_prefix: str = "associated_pipe_flow_id" +) -> dict: """ 查询 scada_info 表中 type 为 'demand' 且 transmission_mode 为 'non_realtime' 的记录, 记录该记录的 associated_pattern。 @@ -289,36 +384,48 @@ def query_pipe_flow_region_patterns(name: str, column_prefix: str = 'associated_ with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: # 查询 type 为 'demand' 且 transmission_mode 为 'non_realtime' 的记录 - cur.execute(""" + cur.execute( + """ SELECT associated_pattern, associated_pipe_flow_id FROM scada_info WHERE type = 'demand' AND transmission_mode = 'non_realtime'; - """) + """ + ) records = cur.fetchall() col_names = [desc.name for desc in cur.description] # 获取列索引 - pattern_idx = col_names.index('associated_pattern') - pipe_flow_id_idx = col_names.index('associated_pipe_flow_id') + pattern_idx = col_names.index("associated_pattern") + pipe_flow_id_idx = col_names.index("associated_pipe_flow_id") for record in records: associated_pattern = record[pattern_idx] associated_pipe_flow_id = record[pipe_flow_id_idx] if associated_pipe_flow_id: # 根据 associated_pipe_flow_id 查询对应的记录 - cur.execute(""" + cur.execute( + """ SELECT associated_pattern, transmission_mode FROM scada_info WHERE associated_element_id = %s; - """, (associated_pipe_flow_id,)) + """, + (associated_pipe_flow_id,), + ) pipe_flow_record = cur.fetchone() if pipe_flow_record: pipe_flow_associated_pattern = pipe_flow_record[0] transmission_mode = pipe_flow_record[1] - if transmission_mode == 'realtime': + if transmission_mode == "realtime": # 将 associated_pattern 记录到字典中 - if pipe_flow_associated_pattern not in globals.pipe_flow_region_patterns: - globals.pipe_flow_region_patterns[pipe_flow_associated_pattern] = [] - globals.pipe_flow_region_patterns[pipe_flow_associated_pattern].append(associated_pattern) + if ( + pipe_flow_associated_pattern + not in globals.pipe_flow_region_patterns + ): + globals.pipe_flow_region_patterns[ + pipe_flow_associated_pattern + ] = [] + globals.pipe_flow_region_patterns[ + pipe_flow_associated_pattern + ].append(associated_pattern) logging.info("生成 pipe_flow_region_patterns 成功。") except psycopg.Error as e: logging.error(f"数据库连接或查询出错: {e}") @@ -352,8 +459,8 @@ def query_SCADA_ID_corresponding_info(name: str, SCADA_ID: str) -> dict: if result: # 将结果转换为字典 associated_info = { - 'associated_element_id': result[0], - 'API_query_id': result[1] + "associated_element_id": result[0], + "API_query_id": result[1], } return associated_info else: @@ -365,8 +472,11 @@ def query_SCADA_ID_corresponding_info(name: str, SCADA_ID: str) -> dict: # 2025/01/11 -def get_source_outflow_region_id(name: str, source_outflow_region: dict, - column_prefix: str = 'associated_source_outflow_id') -> dict: +def get_source_outflow_region_id( + name: str, + source_outflow_region: dict, + column_prefix: str = "associated_source_outflow_id", +) -> dict: """ 基于 source_outflow_region,将其中的 associated_source_outflow_id 替换为对应的 api_query_id, 生成新的字典 source_outflow_region_id。 @@ -376,13 +486,17 @@ def get_source_outflow_region_id(name: str, source_outflow_region: dict, :param column_prefix: 需要提取的列的前缀 :return: 包含区域与对应 api_query_id 的字典 """ - globals.source_outflow_region_id = {region: [] for region in globals.source_outflow_region.keys()} + globals.source_outflow_region_id = { + region: [] for region in globals.source_outflow_region.keys() + } # 提取所有唯一的 associated_source_outflow_id all_ids = set() for ids in globals.source_outflow_region.values(): all_ids.update(ids) if not all_ids: - logging.warning("No associated_source_outflow_id found in source_outflow_region.") + logging.warning( + "No associated_source_outflow_id found in source_outflow_region." + ) return globals.source_outflow_region_id conn_string = get_pgconn_string(db_name=name) try: @@ -410,7 +524,9 @@ def get_source_outflow_region_id(name: str, source_outflow_region: dict, if api_id: globals.source_outflow_region_id[region].append(api_id) else: - logging.warning(f"No api_query_id found for associated_source_outflow_id: {id_}") + logging.warning( + f"No api_query_id found for associated_source_outflow_id: {id_}" + ) except psycopg.Error as e: logging.error(f"数据库连接或查询出错: {e}") except Exception as ex: @@ -419,7 +535,11 @@ def get_source_outflow_region_id(name: str, source_outflow_region: dict, # 2025/01/18 -def get_realtime_region_patterns(name: str, source_outflow_region_id: dict, realtime_region_pipe_flow_and_demand_id: dict) -> (dict, dict): +def get_realtime_region_patterns( + name: str, + source_outflow_region_id: dict, + realtime_region_pipe_flow_and_demand_id: dict, +) -> Tuple[dict, dict]: """ 根据每个 region,从 scada_info 表中查询 api_query_id 对应的 associated_pattern。 将结果分别存储到 source_outflow_region_patterns 和 realtime_region_pipe_flow_and_demand_patterns 两个字典中。 @@ -429,9 +549,12 @@ def get_realtime_region_patterns(name: str, source_outflow_region_id: dict, real :return: source_outflow_region_patterns 和 realtime_region_pipe_flow_and_demand_patterns 两个字典 """ # 初始化返回的字典 - globals.source_outflow_region_patterns = {region: [] for region in globals.source_outflow_region_id.keys()} - globals.realtime_region_pipe_flow_and_demand_patterns = {region: [] for region in - globals.realtime_region_pipe_flow_and_demand_id.keys()} + globals.source_outflow_region_patterns = { + region: [] for region in globals.source_outflow_region_id.keys() + } + globals.realtime_region_pipe_flow_and_demand_patterns = { + region: [] for region in globals.realtime_region_pipe_flow_and_demand_id.keys() + } conn_string = get_pgconn_string(db_name=name) try: with psycopg.connect(conn_string) as conn: @@ -441,35 +564,56 @@ def get_realtime_region_patterns(name: str, source_outflow_region_id: dict, real # 获取 source_outflow_region_id 的 api_query_id 并查询 associated_pattern source_outflow_api_ids = globals.source_outflow_region_id[region] if source_outflow_api_ids: - api_query_ids_str = ", ".join([f"'{api_id}'" for api_id in source_outflow_api_ids]) - cur.execute(f""" + api_query_ids_str = ", ".join( + [f"'{api_id}'" for api_id in source_outflow_api_ids] + ) + cur.execute( + f""" SELECT api_query_id, associated_pattern FROM scada_info WHERE api_query_id IN ({api_query_ids_str}); - """) + """ + ) results = cur.fetchall() globals.source_outflow_region_patterns[region] = [ - associated_pattern for _, associated_pattern in results if associated_pattern + associated_pattern + for _, associated_pattern in results + if associated_pattern ] # 获取 realtime_region_pipe_flow_and_demand_id 的 api_query_id 并查询 associated_pattern - realtime_api_ids = globals.realtime_region_pipe_flow_and_demand_id[region] + realtime_api_ids = globals.realtime_region_pipe_flow_and_demand_id[ + region + ] if realtime_api_ids: - api_query_ids_str = ", ".join([f"'{api_id}'" for api_id in realtime_api_ids]) - cur.execute(f""" + api_query_ids_str = ", ".join( + [f"'{api_id}'" for api_id in realtime_api_ids] + ) + cur.execute( + f""" SELECT api_query_id, associated_pattern FROM scada_info WHERE api_query_id IN ({api_query_ids_str}); - """) + """ + ) results = cur.fetchall() - globals.realtime_region_pipe_flow_and_demand_patterns[region] = [ - associated_pattern for _, associated_pattern in results if associated_pattern + globals.realtime_region_pipe_flow_and_demand_patterns[ + region + ] = [ + associated_pattern + for _, associated_pattern in results + if associated_pattern ] - logging.info("生成 source_outflow_region_patterns 和 realtime_region_pipe_flow_and_demand_patterns 成功。") + logging.info( + "生成 source_outflow_region_patterns 和 realtime_region_pipe_flow_and_demand_patterns 成功。" + ) except psycopg.Error as e: logging.error(f"数据库连接或查询出错: {e}") except Exception as ex: logging.error(f"处理数据时出错: {ex}") - return globals.source_outflow_region_patterns, globals.realtime_region_pipe_flow_and_demand_patterns + return ( + globals.source_outflow_region_patterns, + globals.realtime_region_pipe_flow_and_demand_patterns, + ) def get_pattern_index(cur_datetime: str) -> int: @@ -498,23 +642,23 @@ def get_pattern_index_str(current_time: str) -> str: minN_str = minN_str.zfill(2) hrN_str = str(int(hrN)) hrN_str = hrN_str.zfill(2) - str_i = '{}:{}:00'.format(hrN_str, minN_str) + str_i = "{}:{}:00".format(hrN_str, minN_str) return str_i -def from_seconds_to_clock (secs: int)->str: +def from_seconds_to_clock(secs: int) -> str: """ 从秒格式化为“HH:MM:00”字符串 :param secs: int,秒 :return: str, 以“HH:MM:00”格式返回 """ - hrs=int(secs/3600) - minutes=int((secs-hrs*3600)/60) - seconds=(secs-hrs*3600-minutes*60) - hrs_str=str(hrs).zfill(2) - minutes_str=str(minutes).zfill(2) - seconds_str=str(seconds).zfill(2) - str_clock='{}:{}:{}'.format(hrs_str,minutes_str,seconds_str) + hrs = int(secs / 3600) + minutes = int((secs - hrs * 3600) / 60) + seconds = secs - hrs * 3600 - minutes * 60 + hrs_str = str(hrs).zfill(2) + minutes_str = str(minutes).zfill(2) + seconds_str = str(seconds).zfill(2) + str_clock = "{}:{}:{}".format(hrs_str, minutes_str, seconds_str) return str_clock @@ -524,8 +668,8 @@ def convert_time_format(original_time: str) -> str: :param original_time: str, “2024-04-13T08:00:00+08:00"格式的时间 :return: str,“2024-04-13 08:00:00”格式的时间 """ - new_time = original_time.replace('T', ' ') - new_time = new_time.replace('+08:00', '') + new_time = original_time.replace("T", " ") + new_time = new_time.replace("+08:00", "") return new_time @@ -533,20 +677,32 @@ def get_history_pattern_info(project_name, pattern_name): """读取选定pattern的保存的历史pattern信息flow和factor""" flow_list = [] factor_list = [] - patterns_info = read_all(project_name, - f"select * from history_patterns_flows where id = '{pattern_name}' order by _order") + patterns_info = read_all( + project_name, + f"select * from history_patterns_flows where id = '{pattern_name}' order by _order", + ) for item in patterns_info: - flow_list.append(float(item['flow'])) - factor_list.append(float(item['factor'])) + flow_list.append(float(item["flow"])) + factor_list.append(float(item["factor"])) return flow_list, factor_list # 2025/01/11 -def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: str, modify_total_duration: int = 0, - modify_reservoir_head_pattern: dict[str, list] = None, modify_tank_initial_level: dict[str, float] = None, - modify_junction_base_demand: dict[str, float] = None, modify_junction_damand_pattern: dict[str, list] = None, - modify_fixed_pump_pattern: dict[str, list] = None, modify_variable_pump_pattern: dict[str, list] = None, - modify_valve_opening: dict[str, float] = None, scheme_Type: str = None, scheme_Name: str = None) -> None: +def run_simulation( + name: str, + simulation_type: str, + modify_pattern_start_time: str, + modify_total_duration: int = 0, + modify_reservoir_head_pattern: dict[str, list] = None, + modify_tank_initial_level: dict[str, float] = None, + modify_junction_base_demand: dict[str, float] = None, + modify_junction_damand_pattern: dict[str, list] = None, + modify_fixed_pump_pattern: dict[str, list] = None, + modify_variable_pump_pattern: dict[str, list] = None, + modify_valve_opening: dict[str, float] = None, + scheme_type: str = None, + scheme_name: str = None, +) -> None: """ 传入需要修改的参数,改变数据库中对应位置的值,然后计算,返回结果 :param name: 模型名称,数据库中对应的名字 @@ -560,23 +716,26 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s :param modify_fixed_pump_pattern: dict中包含多个水泵模式,str为工频水泵的id,list为修改后的pattern :param modify_variable_pump_pattern: dict中包含多个水泵模式,str为变频水泵的id,list为修改后的pattern :param modify_valve_opening: dict中包含多个阀门开启度,str为阀门的id,float为修改后的阀门开启度 - :param scheme_Type: 模拟方案类型 - :param scheme_Name:模拟方案名称 + :param scheme_type: 模拟方案类型 + :param scheme_name:模拟方案名称 :return: """ # 记录开始时间 time_cost_start = time.perf_counter() - print('name', name) - print('simulation_type', simulation_type) - print('modify_pattern_start_time', modify_pattern_start_time) - print('modify_total_duration', modify_total_duration) - print('modify_reservoir_head_pattern', modify_reservoir_head_pattern) - print('modify_tank_initial_level', modify_tank_initial_level) - print('modify_junction_base_demand', modify_junction_base_demand) + print("name", name) + print("simulation_type", simulation_type) + print("modify_pattern_start_time", modify_pattern_start_time) + print("modify_total_duration", modify_total_duration) + print("modify_reservoir_head_pattern", modify_reservoir_head_pattern) + print("modify_tank_initial_level", modify_tank_initial_level) + print("modify_junction_base_demand", modify_junction_base_demand) - - print('{} -- Hydraulic simulation started.'.format(datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S'))) + print( + "{} -- Hydraulic simulation started.".format( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + ) + ) # 判断是实时模拟还是多步长模拟 # if simulation_type.upper() == 'REALTIME': # 实时模拟(修改原数据库) @@ -598,11 +757,13 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s print(dic_time) # 获取水力模拟步长,如’0:15:00‘ - globals.hydraulic_timestep = dic_time['HYDRAULIC TIMESTEP'] + globals.hydraulic_timestep = dic_time["HYDRAULIC TIMESTEP"] # 将时间字符串转换为 timedelta 对象 - time_obj = datetime.strptime(globals.hydraulic_timestep, '%H:%M:%S') + time_obj = datetime.strptime(globals.hydraulic_timestep, "%H:%M:%S") # 转换为分钟浮点数 - globals.PATTERN_TIME_STEP = float(time_obj.hour * 60 + time_obj.minute + time_obj.second / 60) + globals.PATTERN_TIME_STEP = float( + time_obj.hour * 60 + time_obj.minute + time_obj.second / 60 + ) # 对输入的时间参数进行处理 pattern_start_time = convert_time_format(modify_pattern_start_time) # 获取模拟开始时间是对应pattern的第几个数 @@ -620,12 +781,14 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s # cs.append(pump_pattern) # set_pattern(name_c, cs) # 修改模拟开始的时间 - str_pattern_start = get_pattern_index_str(convert_time_format(modify_pattern_start_time)) + str_pattern_start = get_pattern_index_str( + convert_time_format(modify_pattern_start_time) + ) dic_time = get_time(name_c) - dic_time['PATTERN START'] = str_pattern_start - dic_time['DURATION'] = from_seconds_to_clock(modify_total_duration) - if simulation_type.upper() == 'REALTIME': - dic_time['DURATION'] = 0 + dic_time["PATTERN START"] = str_pattern_start + dic_time["DURATION"] = from_seconds_to_clock(modify_total_duration) + if simulation_type.upper() == "REALTIME": + dic_time["DURATION"] = 0 cs = ChangeSet() cs.operations.append(dic_time) set_time(name_c, cs) @@ -633,71 +796,109 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s if globals.reservoirs_id: # reservoirs_id = {'ZBBDJSCP000002': '2497', 'R00003': '2571'} # 1.获取reservoir的SCADA数据,形式如{'2497': '3.1231', '2571': '2.7387'} - reservoir_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(globals.reservoirs_id.values()), query_time=modify_pattern_start_time) + reservoir_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(globals.reservoirs_id.values()), + query_time=modify_pattern_start_time, + ) # 2.构建出新字典,形式如{'ZBBDJSCP000002': '3.1231', 'R00003': '2.7387'} - reservoir_dict = {key: reservoir_SCADA_data_dict[value] for key, value in globals.reservoirs_id.items()} + reservoir_dict = { + key: reservoir_SCADA_data_dict[value] + for key, value in globals.reservoirs_id.items() + } # 3.修改reservoir液位模式 for reservoir_name, value in reservoir_dict.items(): if value and float(value) != 0: # 先根据reservoir获取对应的pattern,再对pattern进行修改 - reservoir_pattern = get_pattern(name_c, get_reservoir(name_c, reservoir_name)['pattern']) - reservoir_pattern['factors'][modify_index] = float(value) + globals.RESERVOIR_BASIC_HEIGHT + reservoir_pattern = get_pattern( + name_c, get_reservoir(name_c, reservoir_name)["pattern"] + ) + reservoir_pattern["factors"][modify_index] = ( + float(value) + globals.RESERVOIR_BASIC_HEIGHT + ) cs = ChangeSet() cs.append(reservoir_pattern) set_pattern(name_c, cs) if globals.tanks_id: # 修改tank初始液位 - tank_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(globals.tanks_id.values()), query_time=modify_pattern_start_time) - tank_dict = {key: tank_SCADA_data_dict[value] for key, value in globals.tanks_id.items()} + tank_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(globals.tanks_id.values()), + query_time=modify_pattern_start_time, + ) + tank_dict = { + key: tank_SCADA_data_dict[value] for key, value in globals.tanks_id.items() + } for tank_name, value in tank_dict.items(): if value and float(value) != 0: tank = get_tank(name_c, tank_name) - tank['init_level'] = float(value) + tank["init_level"] = float(value) cs = ChangeSet() cs.append(tank) set_tank(name_c, cs) if globals.fixed_pumps_id: # 修改工频泵的pattern - fixed_pump_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(globals.fixed_pumps_id.values()), query_time=modify_pattern_start_time) + fixed_pump_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(globals.fixed_pumps_id.values()), + query_time=modify_pattern_start_time, + ) # print(fixed_pump_SCADA_data_dict) - fixed_pump_dict = {key: fixed_pump_SCADA_data_dict[value] for key, value in globals.fixed_pumps_id.items()} + fixed_pump_dict = { + key: fixed_pump_SCADA_data_dict[value] + for key, value in globals.fixed_pumps_id.items() + } # print(fixed_pump_dict) for fixed_pump_name, value in fixed_pump_dict.items(): if value: - pump_pattern = get_pattern(name_c, get_pump(name_c, fixed_pump_name)['pattern']) + pump_pattern = get_pattern( + name_c, get_pump(name_c, fixed_pump_name)["pattern"] + ) # print(pump_pattern) - pump_pattern['factors'][modify_index] = float(value) + pump_pattern["factors"][modify_index] = float(value) # print(pump_pattern['factors'][modify_index]) cs = ChangeSet() cs.append(pump_pattern) set_pattern(name_c, cs) if globals.variable_pumps_id: # 修改变频泵的pattern - variable_pump_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(globals.variable_pumps_id.values()), query_time=modify_pattern_start_time) - variable_pump_dict = {key: variable_pump_SCADA_data_dict[value] for key, value in globals.variable_pumps_id.items()} + variable_pump_SCADA_data_dict = ( + TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(globals.variable_pumps_id.values()), + query_time=modify_pattern_start_time, + ) + ) + variable_pump_dict = { + key: variable_pump_SCADA_data_dict[value] + for key, value in globals.variable_pumps_id.items() + } for variable_pump_name, value in variable_pump_dict.items(): if value: - pump_pattern = get_pattern(name_c, get_pump(name_c, variable_pump_name)['pattern']) - pump_pattern['factors'][modify_index] = float(value) / 50 + pump_pattern = get_pattern( + name_c, get_pump(name_c, variable_pump_name)["pattern"] + ) + pump_pattern["factors"][modify_index] = float(value) / 50 cs = ChangeSet() cs.append(pump_pattern) set_pattern(name_c, cs) if globals.demand_id: # 基于实时数据,修改大用户节点的pattern - demand_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(globals.demand_id.values()), query_time=modify_pattern_start_time) - demand_dict = {key: demand_SCADA_data_dict[value] for key, value in globals.demand_id.items()} + demand_SCADA_data_dict = TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(globals.demand_id.values()), + query_time=modify_pattern_start_time, + ) + demand_dict = { + key: demand_SCADA_data_dict[value] + for key, value in globals.demand_id.items() + } for demand_name, value in demand_dict.items(): if value: - demand_pattern = get_pattern(name_c, get_demand(name_c, demand_name)['pattern']) - if get_option(name_c)['UNITS'] == 'LPS': - demand_pattern['factors'][modify_index] = float(value) / 3.6 # 默认SCADA数据获取的是流量单位是m3/h, 转换为 L/s - elif get_option(name_c)['UNITS'] == 'CMH': - demand_pattern['factors'][modify_index] = float(value) + demand_pattern = get_pattern( + name_c, get_demand(name_c, demand_name)["pattern"] + ) + if get_option(name_c)["UNITS"] == "LPS": + demand_pattern["factors"][modify_index] = ( + float(value) / 3.6 + ) # 默认SCADA数据获取的是流量单位是m3/h, 转换为 L/s + elif get_option(name_c)["UNITS"] == "CMH": + demand_pattern["factors"][modify_index] = float(value) cs = ChangeSet() cs.append(demand_pattern) set_pattern(name_c, cs) @@ -705,16 +906,27 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s ############################# if globals.source_outflow_pattern_id: # 基于实时的出厂流量计数据,修改出厂流量计绑定的pattern - source_outflow_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(globals.source_outflow_pattern_id.values()), query_time=modify_pattern_start_time) + source_outflow_SCADA_data_dict = ( + TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(globals.source_outflow_pattern_id.values()), + query_time=modify_pattern_start_time, + ) + ) # print(source_outflow_SCADA_data_dict) - source_outflow_dict = {key: source_outflow_SCADA_data_dict[value] for key, value in globals.source_outflow_pattern_id.items()} + source_outflow_dict = { + key: source_outflow_SCADA_data_dict[value] + for key, value in globals.source_outflow_pattern_id.items() + } # print(source_outflow_dict) for pattern_name in source_outflow_dict.keys(): # print(pattern_name) - history_source_outflow_flow_list, history_source_outflow_factor_list = get_history_pattern_info(name_c, pattern_name) + history_source_outflow_flow_list, history_source_outflow_factor_list = ( + get_history_pattern_info(name_c, pattern_name) + ) history_source_outflow_flow = history_source_outflow_flow_list[modify_index] - history_source_outflow_factor = history_source_outflow_factor_list[modify_index] + history_source_outflow_factor = history_source_outflow_factor_list[ + modify_index + ] # print(source_outflow_dict[pattern_name]) # print(history_source_outflow_flow) # print(history_source_outflow_factor) @@ -723,25 +935,38 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s multiply_factor = realtime_source_outflow / history_source_outflow_flow # print(multiply_factor) pattern = get_pattern(name_c, pattern_name) - pattern['factors'][modify_index] = multiply_factor * history_source_outflow_factor + pattern["factors"][modify_index] = ( + multiply_factor * history_source_outflow_factor + ) # print(pattern['factors'][modify_index]) cs = ChangeSet() cs.append(pattern) set_pattern(name_c, cs) if globals.realtime_pipe_flow_pattern_id: # 基于实时的pipe_flow类数据,修改pipe_flow类绑定的pattern - realtime_pipe_flow_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(globals.realtime_pipe_flow_pattern_id.values()), query_time=modify_pattern_start_time) - realtime_pipe_flow_dict = {key: realtime_pipe_flow_SCADA_data_dict[value] for key, value in globals.realtime_pipe_flow_pattern_id.items()} + realtime_pipe_flow_SCADA_data_dict = ( + TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(globals.realtime_pipe_flow_pattern_id.values()), + query_time=modify_pattern_start_time, + ) + ) + realtime_pipe_flow_dict = { + key: realtime_pipe_flow_SCADA_data_dict[value] + for key, value in globals.realtime_pipe_flow_pattern_id.items() + } for pattern_name in realtime_pipe_flow_dict.keys(): - history_pipe_flow_flow_list, history_pipe_flow_factor_list = get_history_pattern_info(name_c, pattern_name) + history_pipe_flow_flow_list, history_pipe_flow_factor_list = ( + get_history_pattern_info(name_c, pattern_name) + ) history_pipe_flow_flow = history_pipe_flow_flow_list[modify_index] history_pipe_flow_factor = history_pipe_flow_factor_list[modify_index] if realtime_pipe_flow_dict[pattern_name]: realtime_pipe_flow = float(realtime_pipe_flow_dict[pattern_name]) multiply_factor = realtime_pipe_flow / history_pipe_flow_flow pattern = get_pattern(name_c, pattern_name) - pattern['factors'][modify_index] = multiply_factor * history_pipe_flow_factor + pattern["factors"][modify_index] = ( + multiply_factor * history_pipe_flow_factor + ) cs = ChangeSet() cs.append(pattern) set_pattern(name_c, cs) @@ -749,62 +974,145 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s # 基于实时的pipe_flow类数据,修改pipe_flow分区流量计范围内的non_realtime的demand绑定的pattern temp_realtime_pipe_flow_pattern_id = {} # 遍历 pipe_flow_region_patterns 字典的 key - for pipe_flow_region, demand_patterns in globals.pipe_flow_region_patterns.items(): + for ( + pipe_flow_region, + demand_patterns, + ) in globals.pipe_flow_region_patterns.items(): # 获取对应的实时值 query_api_id = globals.realtime_pipe_flow_pattern_id.get(pipe_flow_region) temp_realtime_pipe_flow_pattern_id[pipe_flow_region] = query_api_id - temp_realtime_pipe_flow_SCADA_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=list(temp_realtime_pipe_flow_pattern_id.values()), query_time=modify_pattern_start_time) - temp_realtime_pipe_flow_dict = {key: temp_realtime_pipe_flow_SCADA_data_dict[value] for key, value in temp_realtime_pipe_flow_pattern_id.items()} + temp_realtime_pipe_flow_SCADA_data_dict = ( + TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=list(temp_realtime_pipe_flow_pattern_id.values()), + query_time=modify_pattern_start_time, + ) + ) + temp_realtime_pipe_flow_dict = { + key: temp_realtime_pipe_flow_SCADA_data_dict[value] + for key, value in temp_realtime_pipe_flow_pattern_id.items() + } for pattern_name in temp_realtime_pipe_flow_dict.keys(): - temp_history_pipe_flow_flow_list, temp_history_pipe_flow_factor_list = get_history_pattern_info(name_c, pattern_name) + temp_history_pipe_flow_flow_list, temp_history_pipe_flow_factor_list = ( + get_history_pattern_info(name_c, pattern_name) + ) temp_history_pipe_flow_flow = temp_history_pipe_flow_flow_list[modify_index] if temp_realtime_pipe_flow_dict[pattern_name]: - temp_realtime_pipe_flow = float(temp_realtime_pipe_flow_dict[pattern_name]) - temp_multiply_factor = temp_realtime_pipe_flow / temp_history_pipe_flow_flow - temp_non_realtime_demand_pattern_list = globals.pipe_flow_region_patterns[pattern_name] + temp_realtime_pipe_flow = float( + temp_realtime_pipe_flow_dict[pattern_name] + ) + temp_multiply_factor = ( + temp_realtime_pipe_flow / temp_history_pipe_flow_flow + ) + temp_non_realtime_demand_pattern_list = ( + globals.pipe_flow_region_patterns[pattern_name] + ) for demand_pattern_name in temp_non_realtime_demand_pattern_list: - history_non_realtime_demand_flow_list, history_non_realtime_demand_factor_list = get_history_pattern_info(name_c, demand_pattern_name) - history_non_realtime_demand_factor = history_non_realtime_demand_factor_list[modify_index] + ( + history_non_realtime_demand_flow_list, + history_non_realtime_demand_factor_list, + ) = get_history_pattern_info(name_c, demand_pattern_name) + history_non_realtime_demand_factor = ( + history_non_realtime_demand_factor_list[modify_index] + ) pattern = get_pattern(name_c, demand_pattern_name) - pattern['factors'][modify_index] = temp_multiply_factor * history_non_realtime_demand_factor + pattern["factors"][modify_index] = ( + temp_multiply_factor * history_non_realtime_demand_factor + ) cs = ChangeSet() cs.append(pattern) set_pattern(name_c, cs) if globals.source_outflow_region: # 根据associated_source_outflow_id进行分区,各分区用(出厂的流量计 - 实时的pipe_flow和demand)进行数据更新 for region in globals.source_outflow_region.keys(): - temp_source_outflow_region_id = globals.source_outflow_region_id.get(region, []) - temp_realtime_region_pipe_flow_and_demand_id = globals.realtime_region_pipe_flow_and_demand_id.get(region, []) - temp_source_outflow_region_patterns = globals.source_outflow_region_patterns.get(region, []) - temp_realtime_region_pipe_flow_and_demand_patterns = globals.realtime_region_pipe_flow_and_demand_patterns.get(region, []) - temp_non_realtime_region_patterns = globals.non_realtime_region_patterns.get(region, []) - region_source_outflow_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=temp_source_outflow_region_id, query_time=modify_pattern_start_time) - region_realtime_region_pipe_flow_and_demand_data_dict = influxdb_api.query_SCADA_data_by_device_ID_and_time( - query_ids_list=temp_realtime_region_pipe_flow_and_demand_id, query_time=modify_pattern_start_time) + temp_source_outflow_region_id = globals.source_outflow_region_id.get( + region, [] + ) + temp_realtime_region_pipe_flow_and_demand_id = ( + globals.realtime_region_pipe_flow_and_demand_id.get(region, []) + ) + temp_source_outflow_region_patterns = ( + globals.source_outflow_region_patterns.get(region, []) + ) + temp_realtime_region_pipe_flow_and_demand_patterns = ( + globals.realtime_region_pipe_flow_and_demand_patterns.get(region, []) + ) + temp_non_realtime_region_patterns = ( + globals.non_realtime_region_patterns.get(region, []) + ) + region_source_outflow_data_dict = ( + TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=temp_source_outflow_region_id, + query_time=modify_pattern_start_time, + ) + ) + region_realtime_region_pipe_flow_and_demand_data_dict = ( + TimescaleInternalQueries.query_scada_by_ids_time( + device_ids=temp_realtime_region_pipe_flow_and_demand_id, + query_time=modify_pattern_start_time, + ) + ) # 2025/02/12 确保 region_source_outflow_data_dict 和 # region_realtime_region_pipe_flow_and_demand_data_dict中的每个值都不是 None 且不为 0 - region_source_outflow_valid_values = [float(value) for value in region_source_outflow_data_dict.values() if value not in [None, 0]] - valid_values = [float(value) for value in region_realtime_region_pipe_flow_and_demand_data_dict.values() if value not in [None, 0]] + region_source_outflow_valid_values = [ + float(value) + for value in region_source_outflow_data_dict.values() + if value not in [None, 0] + ] + valid_values = [ + float(value) + for value in region_realtime_region_pipe_flow_and_demand_data_dict.values() + if value not in [None, 0] + ] # 如果都非空,则执行 sum 操作 if region_source_outflow_valid_values and valid_values: region_total_source_outflow = sum(region_source_outflow_valid_values) history_region_total_source_outflow = 0 for source_outflow_pattern_name in temp_source_outflow_region_patterns: - temp_history_source_outflow_flow_list, temp_history_source_outflow_factor_list = get_history_pattern_info(name_c, source_outflow_pattern_name) - history_region_total_source_outflow += temp_history_source_outflow_flow_list[modify_index] + ( + temp_history_source_outflow_flow_list, + temp_history_source_outflow_factor_list, + ) = get_history_pattern_info(name_c, source_outflow_pattern_name) + history_region_total_source_outflow += ( + temp_history_source_outflow_flow_list[modify_index] + ) region_total_realtime_region_pipe_flow_and_demand = sum(valid_values) history_region_total_realtime_region_pipe_flow_and_demand = 0 - for pipe_flow_and_demand_pattern_name in temp_realtime_region_pipe_flow_and_demand_patterns: - temp_history_pipe_flow_and_demand_flow_list, temp_history_pipe_flow_and_demand_factor_list = get_history_pattern_info(name_c, pipe_flow_and_demand_pattern_name) - history_region_total_realtime_region_pipe_flow_and_demand += temp_history_pipe_flow_and_demand_flow_list[modify_index] - temp_multiply_factor = (region_total_source_outflow - region_total_realtime_region_pipe_flow_and_demand) / (history_region_total_source_outflow - history_region_total_realtime_region_pipe_flow_and_demand) - for non_realtime_region_pattern_name in temp_non_realtime_region_patterns: - history_non_realtime_region_pattern_flow_list, history_non_realtime_region_pattern_factor_list = get_history_pattern_info(name_c, non_realtime_region_pattern_name) - history_non_realtime_region_pattern_factor = history_non_realtime_region_pattern_factor_list[modify_index] + for ( + pipe_flow_and_demand_pattern_name + ) in temp_realtime_region_pipe_flow_and_demand_patterns: + ( + temp_history_pipe_flow_and_demand_flow_list, + temp_history_pipe_flow_and_demand_factor_list, + ) = get_history_pattern_info( + name_c, pipe_flow_and_demand_pattern_name + ) + history_region_total_realtime_region_pipe_flow_and_demand += ( + temp_history_pipe_flow_and_demand_flow_list[modify_index] + ) + temp_multiply_factor = ( + region_total_source_outflow + - region_total_realtime_region_pipe_flow_and_demand + ) / ( + history_region_total_source_outflow + - history_region_total_realtime_region_pipe_flow_and_demand + ) + for ( + non_realtime_region_pattern_name + ) in temp_non_realtime_region_patterns: + ( + history_non_realtime_region_pattern_flow_list, + history_non_realtime_region_pattern_factor_list, + ) = get_history_pattern_info( + name_c, non_realtime_region_pattern_name + ) + history_non_realtime_region_pattern_factor = ( + history_non_realtime_region_pattern_factor_list[modify_index] + ) pattern = get_pattern(name_c, non_realtime_region_pattern_name) - pattern['factors'][modify_index] = temp_multiply_factor * history_non_realtime_region_pattern_factor + pattern["factors"][modify_index] = ( + temp_multiply_factor + * history_non_realtime_region_pattern_factor + ) cs = ChangeSet() cs.append(pattern) set_pattern(name_c, cs) @@ -816,20 +1124,27 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s # 如果modify_reservoir_head_pattern[reservoir_name][0]不是NaN,则条件成立,代码块会执行 if not np.isnan(modify_reservoir_head_pattern[reservoir_name][0]): # 给 list 中的所有元素加上 RESERVOIR_BASIC_HEIGHT - modified_values = [value + globals.RESERVOIR_BASIC_HEIGHT for value in - modify_reservoir_head_pattern[reservoir_name]] - reservoir_pattern = get_pattern(name_c, get_reservoir(name_c, reservoir_name)['pattern']) - reservoir_pattern['factors'][modify_index - :modify_index + len(modified_values)] = modified_values + modified_values = [ + value + globals.RESERVOIR_BASIC_HEIGHT + for value in modify_reservoir_head_pattern[reservoir_name] + ] + reservoir_pattern = get_pattern( + name_c, get_reservoir(name_c, reservoir_name)["pattern"] + ) + reservoir_pattern["factors"][ + modify_index : modify_index + len(modified_values) + ] = modified_values cs = ChangeSet() cs.append(reservoir_pattern) set_pattern(name_c, cs) # 修改调节池(tank)初始液位 if modify_tank_initial_level: for tank_name in modify_tank_initial_level.keys(): - if (not np.isnan(modify_tank_initial_level[tank_name])) and (modify_tank_initial_level[tank_name] != 0): + if (not np.isnan(modify_tank_initial_level[tank_name])) and ( + modify_tank_initial_level[tank_name] != 0 + ): tank = get_tank(name_c, tank_name) - tank['init_level'] = modify_tank_initial_level[tank_name] + tank["init_level"] = modify_tank_initial_level[tank_name] cs = ChangeSet() cs.append(tank) set_tank(name_c, cs) @@ -838,7 +1153,7 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s for junction_name in modify_junction_base_demand.keys(): if not np.isnan(modify_junction_base_demand[junction_name]): junction = get_demand(name_c, junction_name) - junction['demand'] = modify_junction_base_demand[junction_name] + junction["demand"] = modify_junction_base_demand[junction_name] cs = ChangeSet() cs.append(junction) set_demand(name_c, cs) @@ -847,9 +1162,10 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s for pattern_name in modify_junction_damand_pattern.keys(): if not np.isnan(modify_junction_damand_pattern[pattern_name][0]): junction_pattern = get_pattern(name_c, pattern_name) - junction_pattern['factors'][modify_index - :modify_index + len(modify_junction_damand_pattern[pattern_name])] \ - = modify_junction_damand_pattern[pattern_name] + junction_pattern["factors"][ + modify_index : modify_index + + len(modify_junction_damand_pattern[pattern_name]) + ] = modify_junction_damand_pattern[pattern_name] cs = ChangeSet() cs.append(junction_pattern) set_pattern(name_c, cs) @@ -857,10 +1173,12 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s if modify_fixed_pump_pattern: for pump_name in modify_fixed_pump_pattern.keys(): if not np.isnan(modify_fixed_pump_pattern[pump_name][0]): - pump_pattern = get_pattern(name_c, get_pump(name_c, pattern_name)['pattern']) - pump_pattern['factors'][modify_index - :modify_index + len(modify_fixed_pump_pattern)] \ - = modify_fixed_pump_pattern[pump_name] + pump_pattern = get_pattern( + name_c, get_pump(name_c, pattern_name)["pattern"] + ) + pump_pattern["factors"][ + modify_index : modify_index + len(modify_fixed_pump_pattern) + ] = modify_fixed_pump_pattern[pump_name] cs = ChangeSet() cs.append(pump_pattern) set_pattern(name_c, cs) @@ -869,10 +1187,15 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s for pump_name in modify_variable_pump_pattern.keys(): if not np.isnan(modify_variable_pump_pattern[pump_name][0]): # 给 list 中的所有元素除以 50Hz - modified_values = [value / 50 for value in modify_variable_pump_pattern[pump_name]] - pump_pattern = get_pattern(name_c, get_pump(name_c, pattern_name)['pattern']) - pump_pattern['factors'][modify_index - :modify_index + len(modified_values)] = modified_values + modified_values = [ + value / 50 for value in modify_variable_pump_pattern[pump_name] + ] + pump_pattern = get_pattern( + name_c, get_pump(name_c, pattern_name)["pattern"] + ) + pump_pattern["factors"][ + modify_index : modify_index + len(modified_values) + ] = modified_values cs = ChangeSet() cs.append(pump_pattern) set_pattern(name_c, cs) @@ -882,49 +1205,90 @@ def run_simulation(name: str, simulation_type: str, modify_pattern_start_time: s if not np.isnan(modify_valve_opening[valve_name]): valve_status = get_status(name_c, valve_name) if modify_valve_opening[valve_name] == 0: - valve_status['status'] = 'CLOSED' - valve_status['setting'] = 0 - if modify_valve_opening[valve_name] < 1: - valve_status['status'] = 'OPEN' - valve_status['setting'] = 0.1036 * pow(modify_valve_opening[valve_name], -3.105) - if modify_valve_opening[valve_name] == 1: - valve_status['status'] = 'OPEN' - valve_status['setting'] = 0 + valve_status["status"] = "CLOSED" + valve_status["setting"] = 0 + elif modify_valve_opening[valve_name] < 1: + valve_status["status"] = "OPEN" + valve_status["setting"] = 0.1036 * pow( + modify_valve_opening[valve_name], -3.105 + ) + elif modify_valve_opening[valve_name] == 1: + valve_status["status"] = "OPEN" + valve_status["setting"] = 0 cs = ChangeSet() cs.append(valve_status) set_status(name_c, cs) - # 运行并返回结果 - result = run_project(name_c) + # 运行并返回结果 + run_project(name_c) time_cost_end = time.perf_counter() - print('{} -- Hydraulic simulation finished, cost time: {:.2f} s.'.format( datetime.now(pytz.timezone('Asia/Shanghai')).strftime('%Y-%m-%d %H:%M:%S'), time_cost_end - time_cost_start)) + print( + "{} -- Hydraulic simulation finished, cost time: {:.2f} s.".format( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S"), + time_cost_end - time_cost_start, + ) + ) # DingZQ 下面这几句一定要这样,不然读取不了 - time.sleep(5) # wait 5 seconds + # time.sleep(5) # wait 5 seconds # TODO: 2025/03/24 # DingZQ 这个名字要用随机数来处理 - tmp_file = f'./temp/simulation_{uuid.uuid4()}.result.out' - shutil.copy(f'./temp/{name_c}.db.opt', tmp_file) + tmp_file = f"./temp/simulation_{uuid.uuid4()}.result.out" + shutil.copy(f"./temp/{name_c}.db.opt", tmp_file) - output = Output(tmp_file) node_result = output.node_results() link_result = output.link_results() - + # link_flow = [] # for link in link_result: # link_flow.append(link['result'][-1]['flow']) # print(link_flow) - num_periods_result = output.times()['num_periods'] + num_periods_result = output.times()["num_periods"] print("simulation_type", simulation_type) print("before store result") # print(num_periods_result) # print(node_result) # 存储 - if simulation_type.upper() == 'REALTIME': - influxdb_api.store_realtime_simulation_result_to_influxdb(node_result, link_result, modify_pattern_start_time) - elif simulation_type.upper() == 'EXTENDED': - influxdb_api.store_scheme_simulation_result_to_influxdb(node_result, link_result, modify_pattern_start_time, num_periods_result, scheme_Type, scheme_Name) - influxdb_api.fill_scheme_simulation_result_to_SCADA(scheme_Type=scheme_Type, scheme_Name=scheme_Name) + starttime = time.time() + # 临时处理输入的name问题,后续需要优化,需要传递/获取iot数据库的名字 + if name.find("_") != -1: + db_name = name.split("_")[2] + else: + db_name = name + if simulation_type.upper() == "REALTIME": + TimescaleInternalStorage.store_realtime_simulation( + node_result, link_result, modify_pattern_start_time, db_name=db_name + ) + elif simulation_type.upper() == "EXTENDED": + TimescaleInternalStorage.store_scheme_simulation( + scheme_type, + scheme_name, + node_result, + link_result, + modify_pattern_start_time, + num_periods_result, + db_name=db_name, + ) + endtime = time.time() + logging.info("store time: %f", endtime - starttime) + # 暂不需要再次存储 SCADA 模拟信息 + # TimescaleInternalQueries.fill_scheme_simulation_result_to_SCADA(scheme_type=scheme_type, scheme_name=scheme_name) + + # if simulation_type.upper() == "REALTIME": + # influxdb_api.store_realtime_simulation_result_to_influxdb( + # node_result, link_result, modify_pattern_start_time + # ) + # elif simulation_type.upper() == "EXTENDED": + # influxdb_api.store_scheme_simulation_result_to_influxdb( + # node_result, + # link_result, + # modify_pattern_start_time, + # num_periods_result, + # scheme_type, + # scheme_name, + # ) + # 暂不需要再次存储 SCADA 模拟信息 + # influxdb_api.fill_scheme_simulation_result_to_SCADA(scheme_type=scheme_type, scheme_name=scheme_name) print("after store result") @@ -938,12 +1302,27 @@ if __name__ == "__main__": query_corresponding_pattern_id_and_query_id(project_info.name) region_result = query_non_realtime_region(project_info.name) - globals.source_outflow_region_id = get_source_outflow_region_id(project_info.name, region_result) - globals.realtime_region_pipe_flow_and_demand_id = query_realtime_region_pipe_flow_and_demand_id(project_info.name, region_result) - globals.pipe_flow_region_patterns = query_pipe_flow_region_patterns(project_info.name) + globals.source_outflow_region_id = get_source_outflow_region_id( + project_info.name, region_result + ) + globals.realtime_region_pipe_flow_and_demand_id = ( + query_realtime_region_pipe_flow_and_demand_id(project_info.name, region_result) + ) + globals.pipe_flow_region_patterns = query_pipe_flow_region_patterns( + project_info.name + ) - globals.non_realtime_region_patterns = query_non_realtime_region_patterns(project_info.name, region_result) - globals.source_outflow_region_patterns, globals.realtime_region_pipe_flow_and_demand_patterns = get_realtime_region_patterns(project_info.name, globals.source_outflow_region_id, globals.realtime_region_pipe_flow_and_demand_id) + globals.non_realtime_region_patterns = query_non_realtime_region_patterns( + project_info.name, region_result + ) + ( + globals.source_outflow_region_patterns, + globals.realtime_region_pipe_flow_and_demand_patterns, + ) = get_realtime_region_patterns( + project_info.name, + globals.source_outflow_region_id, + globals.realtime_region_pipe_flow_and_demand_id, + ) # 基础日期和时间(日期部分保持不变) base_date = datetime(2025, 5, 4) @@ -963,7 +1342,7 @@ if __name__ == "__main__": run_simulation( name=project_info.name, simulation_type="realtime", - modify_pattern_start_time=iso_time + modify_pattern_start_time=iso_time, ) # 打印字典内容以验证 @@ -989,21 +1368,8 @@ if __name__ == "__main__": # run_simulation(name='bb', simulation_type="realtime", modify_pattern_start_time='2025-02-25T23:45:00+08:00') # 模拟示例2 # run_simulation(name='bb', simulation_type="extended", modify_pattern_start_time='2025-03-10T12:00:00+08:00', - # modify_total_duration=1800, scheme_Type="burst_Analysis", scheme_Name="scheme1") + # modify_total_duration=1800, scheme_type="burst_Analysis", scheme_name="scheme1") # 查询示例1:query_SCADA_ID_corresponding_info # result = query_SCADA_ID_corresponding_info(name='bb', SCADA_ID='P10755') # print(result) - - - - - - - - - - - - - diff --git a/app/services/simulation_ops.py b/app/services/simulation_ops.py new file mode 100644 index 0000000..2110deb --- /dev/null +++ b/app/services/simulation_ops.py @@ -0,0 +1,241 @@ +import json +from datetime import datetime +from math import pi + +import pytz + +from app.algorithms.simulation.runner import run_simulation_ex +from app.infra.epanet.epanet import Output +from app.services.tjnetwork import ( + close_project, + copy_project, + delete_project, + get_pipe, + get_tank, + have_project, + is_project_open, + open_project, +) + + +############################################################ +# project management 07 ***暂时不使用,与业务需求无关*** +############################################################ + + +def project_management( + prj_name, + start_datetime, + pump_control, + tank_initial_level_control=None, + region_demand_control=None, +) -> str: + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"project_management_{prj_name}" + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # if is_project_open(prj_name): + # close_project(prj_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(prj_name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(prj_name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + result = run_simulation_ex( + name=new_name, + simulation_type="realtime", + start_datetime=start_datetime, + duration=86400, + pump_control=pump_control, + tank_initial_level_control=tank_initial_level_control, + region_demand_control=region_demand_control, + downloading_prohibition=True, + ) + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + return result + + +############################################################ +# scheduling analysis 08 ***暂时不使用,与业务需求无关*** +############################################################ + + +def scheduling_simulation( + prj_name, start_time, pump_control, tank_id, water_plant_output_id, time_delta=300 +) -> str: + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"scheduling_{prj_name}" + + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # if is_project_open(prj_name): + # close_project(prj_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(prj_name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(prj_name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + + run_simulation_ex( + new_name, "realtime", start_time, duration=0, pump_control=pump_control + ) + + if not is_project_open(new_name): + open_project(new_name) + + tank = get_tank(new_name, tank_id) # 水塔信息 + tank_floor_space = pi * pow(tank["diameter"] / 2, 2) # 水塔底面积(m^2) + tank_init_level = tank["init_level"] # 水塔初始水位(m) + tank_pipes_id = tank["links"] # pipes list + + tank_pipe_flow_direction = ( + {} + ) # 管道流向修正系数, 水塔为下游节点时为1, 水塔为上游节点时为-1 + for pipe_id in tank_pipes_id: + if get_pipe(new_name, pipe_id)["node2"] == tank_id: # 水塔为下游节点 + tank_pipe_flow_direction[pipe_id] = 1 + else: + tank_pipe_flow_direction[pipe_id] = -1 + + output = Output("./temp/{}.db.out".format(new_name)) + + node_results = ( + output.node_results() + ) # [{'node': str, 'result': [{'pressure': float}]}] + water_plant_output_pressure = 0 + for node_result in node_results: + if node_result["node"] == water_plant_output_id: # 水厂出水压力(m) + water_plant_output_pressure = node_result["result"][-1]["pressure"] + water_plant_output_pressure /= 100 # 预计水厂出水压力(Mpa) + + pipe_results = output.link_results() # [{'link': str, 'result': [{'flow': float}]}] + tank_inflow = 0 + for pipe_result in pipe_results: + for pipe_id in tank_pipes_id: # 遍历与水塔相连的管道 + if pipe_result["link"] == pipe_id: # 水塔入流流量(L/s) + tank_inflow += ( + pipe_result["result"][-1]["flow"] + * tank_pipe_flow_direction[pipe_id] + ) + tank_inflow /= 1000 # 水塔入流流量(m^3/s) + tank_level_delta = tank_inflow * time_delta / tank_floor_space # 水塔水位改变值(m) + tank_level = tank_init_level + tank_level_delta # 预计水塔水位(m) + + simulation_results = { + "water_plant_output_pressure": water_plant_output_pressure, + "tank_init_level": tank_init_level, + "tank_level": tank_level, + } + + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + + return json.dumps(simulation_results) + + +def daily_scheduling_simulation( + prj_name, start_time, pump_control, reservoir_id, tank_id, water_plant_output_id +) -> str: + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"daily_scheduling_{prj_name}" + + if have_project(new_name): + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + # if is_project_open(prj_name): + # close_project(prj_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(prj_name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(prj_name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) + open_project(new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + + run_simulation_ex( + new_name, "realtime", start_time, duration=86400, pump_control=pump_control + ) + + if not is_project_open(new_name): + open_project(new_name) + + output = Output("./temp/{}.db.out".format(new_name)) + + node_results = ( + output.node_results() + ) # [{'node': str, 'result': [{'pressure': float, 'head': float}]}] + water_plant_output_pressure = [] + reservoir_level = [] + tank_level = [] + for node_result in node_results: + if node_result["node"] == water_plant_output_id: + for result in node_result["result"]: + water_plant_output_pressure.append( + result["pressure"] / 100 + ) # 水厂出水压力(Mpa) + elif node_result["node"] == reservoir_id: + for result in node_result["result"]: + reservoir_level.append(result["head"] - 250.35) # 清水池液位(m) + elif node_result["node"] == tank_id: + for result in node_result["result"]: + tank_level.append(result["pressure"]) # 调节池液位(m) + + simulation_results = { + "water_plant_output_pressure": water_plant_output_pressure, + "reservoir_level": reservoir_level, + "tank_level": tank_level, + } + + if is_project_open(new_name): + close_project(new_name) + delete_project(new_name) + + return json.dumps(simulation_results) diff --git a/time_api.py b/app/services/time_api.py similarity index 100% rename from time_api.py rename to app/services/time_api.py diff --git a/tjnetwork.py b/app/services/tjnetwork.py similarity index 99% rename from tjnetwork.py rename to app/services/tjnetwork.py index 402496d..a8447e0 100644 --- a/tjnetwork.py +++ b/app/services/tjnetwork.py @@ -1,6 +1,7 @@ from typing import Any -import api -import epanet +import app.native.wndb as api +from app.native.wndb.s36_wda_cal import * +import app.infra.epanet as epanet ############################################################ diff --git a/app/services/valve_isolation.py b/app/services/valve_isolation.py new file mode 100644 index 0000000..993b23e --- /dev/null +++ b/app/services/valve_isolation.py @@ -0,0 +1,11 @@ +from typing import Any + +from app.algorithms.isolation.valve import valve_isolation_analysis + + +def analyze_valve_isolation( + network: str, + accident_element: str | list[str], + disabled_valves: list[str] = None, +) -> dict[str, Any]: + return valve_isolation_analysis(network, accident_element, disabled_valves) diff --git a/app/tasks/__init__.py b/app/tasks/__init__.py new file mode 100644 index 0000000..3ca1a8e --- /dev/null +++ b/app/tasks/__init__.py @@ -0,0 +1,10 @@ +""" +This module is reserved for future implementation of background tasks and job queues. + +Currently, most operations are handled synchronously or via simple async functions in `app.services`. +Future expansion may include: +- Integration with task queues like Celery or RQ +- Scheduled jobs (Cron-like) for maintenance and data synchronization +- Long-running simulation orchestration +- Email/Notification dispatching +""" diff --git a/app/utils/__init__.py b/app/utils/__init__.py new file mode 100644 index 0000000..04f21c8 --- /dev/null +++ b/app/utils/__init__.py @@ -0,0 +1,13 @@ +""" +This module is reserved for general utility functions and helpers. + +Currently, specific utilities are often implemented within their respective service modules +(e.g., time handling in `app.services.time_api`) or core modules. + +Future expansion may include: +- Date and time manipulation helpers +- String and text processing utilities +- File I/O and path management tools +- Mathematical and unit conversion functions +- Network and IP address utilities +""" diff --git a/build/lib.win-amd64-cpython-312/api/__init__.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/__init__.cp312-win_amd64.pyd deleted file mode 100644 index a3a240c..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/__init__.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/batch_api.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/batch_api.cp312-win_amd64.pyd deleted file mode 100644 index 0980c0e..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/batch_api.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/batch_api_cs.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/batch_api_cs.cp312-win_amd64.pyd deleted file mode 100644 index e538e7c..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/batch_api_cs.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/batch_exe.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/batch_exe.cp312-win_amd64.pyd deleted file mode 100644 index d97078d..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/batch_exe.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/clean_api.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/clean_api.cp312-win_amd64.pyd deleted file mode 100644 index eccc8a1..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/clean_api.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/connection.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/connection.cp312-win_amd64.pyd deleted file mode 100644 index d75a2e8..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/connection.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/database.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/database.cp312-win_amd64.pyd deleted file mode 100644 index 456c952..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/database.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/extension_data.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/extension_data.cp312-win_amd64.pyd deleted file mode 100644 index d4d2e52..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/extension_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/inp_in.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/inp_in.cp312-win_amd64.pyd deleted file mode 100644 index d9ee4f5..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/inp_in.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/inp_out.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/inp_out.cp312-win_amd64.pyd deleted file mode 100644 index f7a6b42..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/inp_out.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/project.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/project.cp312-win_amd64.pyd deleted file mode 100644 index 22cde34..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/project.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s0_base.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s0_base.cp312-win_amd64.pyd deleted file mode 100644 index a6f9d78..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s0_base.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s10_status.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s10_status.cp312-win_amd64.pyd deleted file mode 100644 index e41bed0..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s10_status.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s11_patterns.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s11_patterns.cp312-win_amd64.pyd deleted file mode 100644 index 2f1482a..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s11_patterns.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s12_curves.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s12_curves.cp312-win_amd64.pyd deleted file mode 100644 index ec57b98..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s12_curves.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s13_controls.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s13_controls.cp312-win_amd64.pyd deleted file mode 100644 index d145a33..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s13_controls.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s14_rules.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s14_rules.cp312-win_amd64.pyd deleted file mode 100644 index 929f161..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s14_rules.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s15_energy.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s15_energy.cp312-win_amd64.pyd deleted file mode 100644 index 187f7b4..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s15_energy.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s16_emitters.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s16_emitters.cp312-win_amd64.pyd deleted file mode 100644 index f3960e4..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s16_emitters.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s17_quality.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s17_quality.cp312-win_amd64.pyd deleted file mode 100644 index 4b2edf4..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s17_quality.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s18_sources.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s18_sources.cp312-win_amd64.pyd deleted file mode 100644 index 631d822..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s18_sources.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s19_reactions.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s19_reactions.cp312-win_amd64.pyd deleted file mode 100644 index 52fdc77..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s19_reactions.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s1_title.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s1_title.cp312-win_amd64.pyd deleted file mode 100644 index 1a655b4..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s1_title.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s20_mixing.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s20_mixing.cp312-win_amd64.pyd deleted file mode 100644 index 091ac50..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s20_mixing.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s21_times.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s21_times.cp312-win_amd64.pyd deleted file mode 100644 index 54b5d38..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s21_times.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s22_report.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s22_report.cp312-win_amd64.pyd deleted file mode 100644 index 2649bfa..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s22_report.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s23_options.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s23_options.cp312-win_amd64.pyd deleted file mode 100644 index ae049de..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s23_options.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s23_options_util.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s23_options_util.cp312-win_amd64.pyd deleted file mode 100644 index eb79b54..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s23_options_util.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s23_options_v3.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s23_options_v3.cp312-win_amd64.pyd deleted file mode 100644 index 6652f07..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s23_options_v3.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s24_coordinates.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s24_coordinates.cp312-win_amd64.pyd deleted file mode 100644 index a15635d..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s24_coordinates.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s25_vertices.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s25_vertices.cp312-win_amd64.pyd deleted file mode 100644 index dd81849..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s25_vertices.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s26_labels.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s26_labels.cp312-win_amd64.pyd deleted file mode 100644 index dac3320..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s26_labels.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s27_backdrop.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s27_backdrop.cp312-win_amd64.pyd deleted file mode 100644 index 92abd66..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s27_backdrop.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s28_end.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s28_end.cp312-win_amd64.pyd deleted file mode 100644 index e517e15..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s28_end.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s29_scada_device.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s29_scada_device.cp312-win_amd64.pyd deleted file mode 100644 index 32c8e07..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s29_scada_device.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s2_junctions.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s2_junctions.cp312-win_amd64.pyd deleted file mode 100644 index a78ba14..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s2_junctions.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s30_scada_device_data.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s30_scada_device_data.cp312-win_amd64.pyd deleted file mode 100644 index 2c09cea..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s30_scada_device_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s31_scada_element.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s31_scada_element.cp312-win_amd64.pyd deleted file mode 100644 index 11086ee..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s31_scada_element.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s32_region.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s32_region.cp312-win_amd64.pyd deleted file mode 100644 index 827b33b..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s32_region.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s32_region_util.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s32_region_util.cp312-win_amd64.pyd deleted file mode 100644 index d587c43..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s32_region_util.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s33_dma.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s33_dma.cp312-win_amd64.pyd deleted file mode 100644 index 8444030..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s33_dma.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s33_dma_cal.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s33_dma_cal.cp312-win_amd64.pyd deleted file mode 100644 index 1914194..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s33_dma_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s33_dma_gen.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s33_dma_gen.cp312-win_amd64.pyd deleted file mode 100644 index 660709e..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s33_dma_gen.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s34_sa.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s34_sa.cp312-win_amd64.pyd deleted file mode 100644 index bb1082b..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s34_sa.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s34_sa_cal.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s34_sa_cal.cp312-win_amd64.pyd deleted file mode 100644 index aa9868f..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s34_sa_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s34_sa_gen.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s34_sa_gen.cp312-win_amd64.pyd deleted file mode 100644 index c5419f4..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s34_sa_gen.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s35_vd.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s35_vd.cp312-win_amd64.pyd deleted file mode 100644 index 1608fef..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s35_vd.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s35_vd_cal.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s35_vd_cal.cp312-win_amd64.pyd deleted file mode 100644 index e7066fb..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s35_vd_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s35_vd_gen.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s35_vd_gen.cp312-win_amd64.pyd deleted file mode 100644 index 45b979b..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s35_vd_gen.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s36_wda.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s36_wda.cp312-win_amd64.pyd deleted file mode 100644 index 21988b5..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s36_wda.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s36_wda_cal.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s36_wda_cal.cp312-win_amd64.pyd deleted file mode 100644 index ace548a..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s36_wda_cal.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s38_scada_info.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s38_scada_info.cp312-win_amd64.pyd deleted file mode 100644 index ac1aec5..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s38_scada_info.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s39_user.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s39_user.cp312-win_amd64.pyd deleted file mode 100644 index ee37ac0..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s39_user.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s3_reservoirs.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s3_reservoirs.cp312-win_amd64.pyd deleted file mode 100644 index d516ad5..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s3_reservoirs.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s40_schema.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s40_schema.cp312-win_amd64.pyd deleted file mode 100644 index b872a02..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s40_schema.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s41_pipe_risk_probability.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s41_pipe_risk_probability.cp312-win_amd64.pyd deleted file mode 100644 index 0cdb21c..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s41_pipe_risk_probability.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s42_sensor_placement.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s42_sensor_placement.cp312-win_amd64.pyd deleted file mode 100644 index b391113..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s42_sensor_placement.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s43_burst_locate_result.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s43_burst_locate_result.cp312-win_amd64.pyd deleted file mode 100644 index cf40653..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s43_burst_locate_result.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s4_tanks.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s4_tanks.cp312-win_amd64.pyd deleted file mode 100644 index 982c73f..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s4_tanks.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s5_pipes.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s5_pipes.cp312-win_amd64.pyd deleted file mode 100644 index c8fee35..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s5_pipes.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s6_pumps.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s6_pumps.cp312-win_amd64.pyd deleted file mode 100644 index 0385f70..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s6_pumps.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s7_valves.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s7_valves.cp312-win_amd64.pyd deleted file mode 100644 index 0c0b967..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s7_valves.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s8_tags.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s8_tags.cp312-win_amd64.pyd deleted file mode 100644 index 827e8c6..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s8_tags.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/s9_demands.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/s9_demands.cp312-win_amd64.pyd deleted file mode 100644 index 860d691..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/s9_demands.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/api/sections.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/api/sections.cp312-win_amd64.pyd deleted file mode 100644 index ffc26bb..0000000 Binary files a/build/lib.win-amd64-cpython-312/api/sections.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/auto_realtime.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/auto_realtime.cp312-win_amd64.pyd deleted file mode 100644 index 66cd316..0000000 Binary files a/build/lib.win-amd64-cpython-312/auto_realtime.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/auto_store_non_realtime_SCADA_data.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/auto_store_non_realtime_SCADA_data.cp312-win_amd64.pyd deleted file mode 100644 index 5e55062..0000000 Binary files a/build/lib.win-amd64-cpython-312/auto_store_non_realtime_SCADA_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/epanet/__init__.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/epanet/__init__.cp312-win_amd64.pyd deleted file mode 100644 index a62f9cb..0000000 Binary files a/build/lib.win-amd64-cpython-312/epanet/__init__.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/epanet/epanet.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/epanet/epanet.cp312-win_amd64.pyd deleted file mode 100644 index 83603d7..0000000 Binary files a/build/lib.win-amd64-cpython-312/epanet/epanet.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/epanet/epanet2_ec.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/epanet/epanet2_ec.cp312-win_amd64.pyd deleted file mode 100644 index 604207f..0000000 Binary files a/build/lib.win-amd64-cpython-312/epanet/epanet2_ec.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/get_current_status.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/get_current_status.cp312-win_amd64.pyd deleted file mode 100644 index 2ee8e8e..0000000 Binary files a/build/lib.win-amd64-cpython-312/get_current_status.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/get_current_total_Q.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/get_current_total_Q.cp312-win_amd64.pyd deleted file mode 100644 index f139098..0000000 Binary files a/build/lib.win-amd64-cpython-312/get_current_total_Q.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/get_data.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/get_data.cp312-win_amd64.pyd deleted file mode 100644 index f369b47..0000000 Binary files a/build/lib.win-amd64-cpython-312/get_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/get_hist_data.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/get_hist_data.cp312-win_amd64.pyd deleted file mode 100644 index 576a286..0000000 Binary files a/build/lib.win-amd64-cpython-312/get_hist_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/get_realValue.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/get_realValue.cp312-win_amd64.pyd deleted file mode 100644 index ee63f1c..0000000 Binary files a/build/lib.win-amd64-cpython-312/get_realValue.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/influxdb_api.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/influxdb_api.cp312-win_amd64.pyd deleted file mode 100644 index d0f4faa..0000000 Binary files a/build/lib.win-amd64-cpython-312/influxdb_api.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/influxdb_query_SCADA_data.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/influxdb_query_SCADA_data.cp312-win_amd64.pyd deleted file mode 100644 index 12f9ea7..0000000 Binary files a/build/lib.win-amd64-cpython-312/influxdb_query_SCADA_data.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/main.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/main.cp312-win_amd64.pyd deleted file mode 100644 index 1e45c67..0000000 Binary files a/build/lib.win-amd64-cpython-312/main.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/online_Analysis.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/online_Analysis.cp312-win_amd64.pyd deleted file mode 100644 index f7e4a63..0000000 Binary files a/build/lib.win-amd64-cpython-312/online_Analysis.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/run_simlation.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/run_simlation.cp312-win_amd64.pyd deleted file mode 100644 index 4984eff..0000000 Binary files a/build/lib.win-amd64-cpython-312/run_simlation.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/run_simulation.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/run_simulation.cp312-win_amd64.pyd deleted file mode 100644 index 632df84..0000000 Binary files a/build/lib.win-amd64-cpython-312/run_simulation.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/sensitivity.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/sensitivity.cp312-win_amd64.pyd deleted file mode 100644 index f8d53d2..0000000 Binary files a/build/lib.win-amd64-cpython-312/sensitivity.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/sensor_placement.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/sensor_placement.cp312-win_amd64.pyd deleted file mode 100644 index e81ed03..0000000 Binary files a/build/lib.win-amd64-cpython-312/sensor_placement.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/simulation.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/simulation.cp312-win_amd64.pyd deleted file mode 100644 index 34fb951..0000000 Binary files a/build/lib.win-amd64-cpython-312/simulation.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/time_api.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/time_api.cp312-win_amd64.pyd deleted file mode 100644 index 06f418a..0000000 Binary files a/build/lib.win-amd64-cpython-312/time_api.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/lib.win-amd64-cpython-312/tjnetwork.cp312-win_amd64.pyd b/build/lib.win-amd64-cpython-312/tjnetwork.cp312-win_amd64.pyd deleted file mode 100644 index 3df6d9f..0000000 Binary files a/build/lib.win-amd64-cpython-312/tjnetwork.cp312-win_amd64.pyd and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/__init__.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/__init__.cp312-win_amd64.exp deleted file mode 100644 index 7ad15cf..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/__init__.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/__init__.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/__init__.cp312-win_amd64.lib deleted file mode 100644 index 7025242..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/__init__.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/__init__.obj b/build/temp.win-amd64-cpython-312/Release/api/__init__.obj deleted file mode 100644 index 78ab8b7..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/__init__.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_api.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/batch_api.cp312-win_amd64.exp deleted file mode 100644 index 101bf33..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_api.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_api.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/batch_api.cp312-win_amd64.lib deleted file mode 100644 index 2ed382c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_api.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_api.obj b/build/temp.win-amd64-cpython-312/Release/api/batch_api.obj deleted file mode 100644 index d06f03a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_api.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.cp312-win_amd64.exp deleted file mode 100644 index 8e2205e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.cp312-win_amd64.lib deleted file mode 100644 index 7cc41ed..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.obj b/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.obj deleted file mode 100644 index 2f940c7..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_api_cs.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_exe.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/batch_exe.cp312-win_amd64.exp deleted file mode 100644 index 94c6536..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_exe.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_exe.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/batch_exe.cp312-win_amd64.lib deleted file mode 100644 index b8354ff..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_exe.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/batch_exe.obj b/build/temp.win-amd64-cpython-312/Release/api/batch_exe.obj deleted file mode 100644 index 909c4b0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/batch_exe.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/clean_api.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/clean_api.cp312-win_amd64.exp deleted file mode 100644 index fb39f0f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/clean_api.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/clean_api.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/clean_api.cp312-win_amd64.lib deleted file mode 100644 index f186bee..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/clean_api.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/clean_api.obj b/build/temp.win-amd64-cpython-312/Release/api/clean_api.obj deleted file mode 100644 index 0ba189c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/clean_api.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/connection.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/connection.cp312-win_amd64.exp deleted file mode 100644 index a07e353..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/connection.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/connection.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/connection.cp312-win_amd64.lib deleted file mode 100644 index e70a24e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/connection.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/connection.obj b/build/temp.win-amd64-cpython-312/Release/api/connection.obj deleted file mode 100644 index 21ae002..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/connection.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/database.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/database.cp312-win_amd64.exp deleted file mode 100644 index 9cf11ce..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/database.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/database.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/database.cp312-win_amd64.lib deleted file mode 100644 index 375e6f4..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/database.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/database.obj b/build/temp.win-amd64-cpython-312/Release/api/database.obj deleted file mode 100644 index 3b0778a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/database.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/extension_data.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/extension_data.cp312-win_amd64.exp deleted file mode 100644 index 74dbfa5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/extension_data.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/extension_data.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/extension_data.cp312-win_amd64.lib deleted file mode 100644 index 856d839..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/extension_data.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/extension_data.obj b/build/temp.win-amd64-cpython-312/Release/api/extension_data.obj deleted file mode 100644 index a7c77af..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/extension_data.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/inp_in.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/inp_in.cp312-win_amd64.exp deleted file mode 100644 index c8b4b27..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/inp_in.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/inp_in.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/inp_in.cp312-win_amd64.lib deleted file mode 100644 index d2c79c0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/inp_in.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/inp_in.obj b/build/temp.win-amd64-cpython-312/Release/api/inp_in.obj deleted file mode 100644 index 322f387..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/inp_in.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/inp_out.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/inp_out.cp312-win_amd64.exp deleted file mode 100644 index 44fd886..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/inp_out.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/inp_out.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/inp_out.cp312-win_amd64.lib deleted file mode 100644 index ba9cdf5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/inp_out.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/inp_out.obj b/build/temp.win-amd64-cpython-312/Release/api/inp_out.obj deleted file mode 100644 index efd985b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/inp_out.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/project.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/project.cp312-win_amd64.exp deleted file mode 100644 index ffdc6ac..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/project.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/project.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/project.cp312-win_amd64.lib deleted file mode 100644 index f3a64d1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/project.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/project.obj b/build/temp.win-amd64-cpython-312/Release/api/project.obj deleted file mode 100644 index 5e35683..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/project.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s0_base.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s0_base.cp312-win_amd64.exp deleted file mode 100644 index 503278d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s0_base.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s0_base.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s0_base.cp312-win_amd64.lib deleted file mode 100644 index 01a3365..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s0_base.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s0_base.obj b/build/temp.win-amd64-cpython-312/Release/api/s0_base.obj deleted file mode 100644 index a31d9d0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s0_base.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s10_status.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s10_status.cp312-win_amd64.exp deleted file mode 100644 index dc05d7f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s10_status.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s10_status.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s10_status.cp312-win_amd64.lib deleted file mode 100644 index 56108ce..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s10_status.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s10_status.obj b/build/temp.win-amd64-cpython-312/Release/api/s10_status.obj deleted file mode 100644 index fc79cec..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s10_status.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.cp312-win_amd64.exp deleted file mode 100644 index 82a74ef..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.cp312-win_amd64.lib deleted file mode 100644 index aa1dd81..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.obj b/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.obj deleted file mode 100644 index 3b57a77..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s11_patterns.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s12_curves.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s12_curves.cp312-win_amd64.exp deleted file mode 100644 index 9026dc0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s12_curves.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s12_curves.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s12_curves.cp312-win_amd64.lib deleted file mode 100644 index 2e30ff1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s12_curves.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s12_curves.obj b/build/temp.win-amd64-cpython-312/Release/api/s12_curves.obj deleted file mode 100644 index 844b448..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s12_curves.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s13_controls.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s13_controls.cp312-win_amd64.exp deleted file mode 100644 index 9708823..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s13_controls.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s13_controls.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s13_controls.cp312-win_amd64.lib deleted file mode 100644 index 477d693..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s13_controls.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s13_controls.obj b/build/temp.win-amd64-cpython-312/Release/api/s13_controls.obj deleted file mode 100644 index f4d8fdd..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s13_controls.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s14_rules.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s14_rules.cp312-win_amd64.exp deleted file mode 100644 index 0bfb0f0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s14_rules.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s14_rules.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s14_rules.cp312-win_amd64.lib deleted file mode 100644 index 5d8684a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s14_rules.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s14_rules.obj b/build/temp.win-amd64-cpython-312/Release/api/s14_rules.obj deleted file mode 100644 index c2f5028..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s14_rules.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s15_energy.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s15_energy.cp312-win_amd64.exp deleted file mode 100644 index 264ff12..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s15_energy.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s15_energy.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s15_energy.cp312-win_amd64.lib deleted file mode 100644 index 2baae01..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s15_energy.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s15_energy.obj b/build/temp.win-amd64-cpython-312/Release/api/s15_energy.obj deleted file mode 100644 index 94344c1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s15_energy.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.cp312-win_amd64.exp deleted file mode 100644 index 74de62f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.cp312-win_amd64.lib deleted file mode 100644 index 34af71b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.obj b/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.obj deleted file mode 100644 index 68be098..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s16_emitters.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s17_quality.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s17_quality.cp312-win_amd64.exp deleted file mode 100644 index ebb0c4b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s17_quality.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s17_quality.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s17_quality.cp312-win_amd64.lib deleted file mode 100644 index aab67a8..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s17_quality.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s17_quality.obj b/build/temp.win-amd64-cpython-312/Release/api/s17_quality.obj deleted file mode 100644 index d59fb37..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s17_quality.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s18_sources.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s18_sources.cp312-win_amd64.exp deleted file mode 100644 index 19938f5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s18_sources.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s18_sources.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s18_sources.cp312-win_amd64.lib deleted file mode 100644 index 806f7de..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s18_sources.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s18_sources.obj b/build/temp.win-amd64-cpython-312/Release/api/s18_sources.obj deleted file mode 100644 index 7bbd6d2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s18_sources.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.cp312-win_amd64.exp deleted file mode 100644 index 9c2c7f0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.cp312-win_amd64.lib deleted file mode 100644 index 50b8ead..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.obj b/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.obj deleted file mode 100644 index d8598a6..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s19_reactions.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s1_title.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s1_title.cp312-win_amd64.exp deleted file mode 100644 index d82dde3..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s1_title.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s1_title.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s1_title.cp312-win_amd64.lib deleted file mode 100644 index 98ca71c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s1_title.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s1_title.obj b/build/temp.win-amd64-cpython-312/Release/api/s1_title.obj deleted file mode 100644 index 8c48236..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s1_title.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.cp312-win_amd64.exp deleted file mode 100644 index ef59f9f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.cp312-win_amd64.lib deleted file mode 100644 index e003c89..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.obj b/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.obj deleted file mode 100644 index 0dcf0d2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s20_mixing.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s21_times.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s21_times.cp312-win_amd64.exp deleted file mode 100644 index 8e9b103..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s21_times.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s21_times.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s21_times.cp312-win_amd64.lib deleted file mode 100644 index 828f0e3..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s21_times.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s21_times.obj b/build/temp.win-amd64-cpython-312/Release/api/s21_times.obj deleted file mode 100644 index 081b16d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s21_times.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s22_report.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s22_report.cp312-win_amd64.exp deleted file mode 100644 index 1a6d57c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s22_report.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s22_report.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s22_report.cp312-win_amd64.lib deleted file mode 100644 index 86d78fd..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s22_report.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s22_report.obj b/build/temp.win-amd64-cpython-312/Release/api/s22_report.obj deleted file mode 100644 index ca8d405..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s22_report.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s23_options.cp312-win_amd64.exp deleted file mode 100644 index 7f20dcd..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s23_options.cp312-win_amd64.lib deleted file mode 100644 index 38f445c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options.obj b/build/temp.win-amd64-cpython-312/Release/api/s23_options.obj deleted file mode 100644 index 57aa386..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.cp312-win_amd64.exp deleted file mode 100644 index 6d4ae7b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.cp312-win_amd64.lib deleted file mode 100644 index f64678d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.obj b/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.obj deleted file mode 100644 index 8c64058..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options_util.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.cp312-win_amd64.exp deleted file mode 100644 index 21dd3de..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.cp312-win_amd64.lib deleted file mode 100644 index 74aa8c3..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.obj b/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.obj deleted file mode 100644 index b7c700d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s23_options_v3.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.cp312-win_amd64.exp deleted file mode 100644 index 7a81939..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.cp312-win_amd64.lib deleted file mode 100644 index 903ac09..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.obj b/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.obj deleted file mode 100644 index 9f3693e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s24_coordinates.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.cp312-win_amd64.exp deleted file mode 100644 index c3f897d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.cp312-win_amd64.lib deleted file mode 100644 index 7bd7046..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.obj b/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.obj deleted file mode 100644 index 07da5c1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s25_vertices.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s26_labels.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s26_labels.cp312-win_amd64.exp deleted file mode 100644 index 2fadb0e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s26_labels.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s26_labels.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s26_labels.cp312-win_amd64.lib deleted file mode 100644 index a70be8d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s26_labels.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s26_labels.obj b/build/temp.win-amd64-cpython-312/Release/api/s26_labels.obj deleted file mode 100644 index cd08c3a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s26_labels.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.cp312-win_amd64.exp deleted file mode 100644 index 28d150f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.cp312-win_amd64.lib deleted file mode 100644 index e28992e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.obj b/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.obj deleted file mode 100644 index 5f77ed2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s27_backdrop.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s28_end.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s28_end.cp312-win_amd64.exp deleted file mode 100644 index 676894e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s28_end.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s28_end.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s28_end.cp312-win_amd64.lib deleted file mode 100644 index 02cb332..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s28_end.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s28_end.obj b/build/temp.win-amd64-cpython-312/Release/api/s28_end.obj deleted file mode 100644 index a673f39..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s28_end.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.cp312-win_amd64.exp deleted file mode 100644 index 50d77dd..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.cp312-win_amd64.lib deleted file mode 100644 index 91fa4ab..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.obj b/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.obj deleted file mode 100644 index aa16197..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s29_scada_device.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.cp312-win_amd64.exp deleted file mode 100644 index aff866c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.cp312-win_amd64.lib deleted file mode 100644 index fd3e15b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.obj b/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.obj deleted file mode 100644 index 4c5e1bf..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s2_junctions.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.cp312-win_amd64.exp deleted file mode 100644 index b7320b1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.cp312-win_amd64.lib deleted file mode 100644 index f05da54..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.obj b/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.obj deleted file mode 100644 index 0737c20..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s30_scada_device_data.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.cp312-win_amd64.exp deleted file mode 100644 index a754578..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.cp312-win_amd64.lib deleted file mode 100644 index 402decd..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.obj b/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.obj deleted file mode 100644 index adb5416..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s31_scada_element.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s32_region.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s32_region.cp312-win_amd64.exp deleted file mode 100644 index f1f7f9f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s32_region.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s32_region.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s32_region.cp312-win_amd64.lib deleted file mode 100644 index d398fd9..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s32_region.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s32_region.obj b/build/temp.win-amd64-cpython-312/Release/api/s32_region.obj deleted file mode 100644 index 246406c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s32_region.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.cp312-win_amd64.exp deleted file mode 100644 index 016d506..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.cp312-win_amd64.lib deleted file mode 100644 index d17f6fe..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.obj b/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.obj deleted file mode 100644 index 07a67c1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s32_region_util.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s33_dma.cp312-win_amd64.exp deleted file mode 100644 index 4674d92..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s33_dma.cp312-win_amd64.lib deleted file mode 100644 index 9fbd199..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma.obj b/build/temp.win-amd64-cpython-312/Release/api/s33_dma.obj deleted file mode 100644 index 4960796..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.cp312-win_amd64.exp deleted file mode 100644 index 2ba456c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.cp312-win_amd64.lib deleted file mode 100644 index bd7fcbb..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.obj b/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.obj deleted file mode 100644 index 11406b4..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_cal.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.cp312-win_amd64.exp deleted file mode 100644 index 7680902..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.cp312-win_amd64.lib deleted file mode 100644 index ab6a62e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.obj b/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.obj deleted file mode 100644 index 70ae0a6..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s33_dma_gen.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s34_sa.cp312-win_amd64.exp deleted file mode 100644 index 80184bc..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s34_sa.cp312-win_amd64.lib deleted file mode 100644 index 67b3b65..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa.obj b/build/temp.win-amd64-cpython-312/Release/api/s34_sa.obj deleted file mode 100644 index d3d8bc5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.cp312-win_amd64.exp deleted file mode 100644 index f436cd8..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.cp312-win_amd64.lib deleted file mode 100644 index b2a5330..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.obj b/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.obj deleted file mode 100644 index 6beb319..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_cal.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.cp312-win_amd64.exp deleted file mode 100644 index b823f59..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.cp312-win_amd64.lib deleted file mode 100644 index 33d1141..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.obj b/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.obj deleted file mode 100644 index e590850..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s34_sa_gen.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s35_vd.cp312-win_amd64.exp deleted file mode 100644 index a973294..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s35_vd.cp312-win_amd64.lib deleted file mode 100644 index e4d0a06..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd.obj b/build/temp.win-amd64-cpython-312/Release/api/s35_vd.obj deleted file mode 100644 index ef70d6f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.cp312-win_amd64.exp deleted file mode 100644 index dc995e7..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.cp312-win_amd64.lib deleted file mode 100644 index 016c85e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.obj b/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.obj deleted file mode 100644 index e0d0ae1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_cal.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.cp312-win_amd64.exp deleted file mode 100644 index 35c4e1a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.cp312-win_amd64.lib deleted file mode 100644 index a545fad..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.obj b/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.obj deleted file mode 100644 index 04a27d2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s35_vd_gen.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s36_wda.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s36_wda.cp312-win_amd64.exp deleted file mode 100644 index f97e099..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s36_wda.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s36_wda.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s36_wda.cp312-win_amd64.lib deleted file mode 100644 index f8e6c92..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s36_wda.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s36_wda.obj b/build/temp.win-amd64-cpython-312/Release/api/s36_wda.obj deleted file mode 100644 index 79a3a92..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s36_wda.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.cp312-win_amd64.exp deleted file mode 100644 index 021e985..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.cp312-win_amd64.lib deleted file mode 100644 index 347c455..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.obj b/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.obj deleted file mode 100644 index a135346..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s36_wda_cal.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.cp312-win_amd64.exp deleted file mode 100644 index fcf4024..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.cp312-win_amd64.lib deleted file mode 100644 index 18859e8..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.obj b/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.obj deleted file mode 100644 index 2e097c9..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s38_scada_info.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s39_user.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s39_user.cp312-win_amd64.exp deleted file mode 100644 index a7091a2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s39_user.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s39_user.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s39_user.cp312-win_amd64.lib deleted file mode 100644 index 4f7273a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s39_user.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s39_user.obj b/build/temp.win-amd64-cpython-312/Release/api/s39_user.obj deleted file mode 100644 index b94c33d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s39_user.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.cp312-win_amd64.exp deleted file mode 100644 index d5c0a0b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.cp312-win_amd64.lib deleted file mode 100644 index 9e8dff7..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.obj b/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.obj deleted file mode 100644 index 0cbe8a4..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s3_reservoirs.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s40_schema.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s40_schema.cp312-win_amd64.exp deleted file mode 100644 index dbbe6db..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s40_schema.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s40_schema.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s40_schema.cp312-win_amd64.lib deleted file mode 100644 index 169e5b0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s40_schema.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s40_schema.obj b/build/temp.win-amd64-cpython-312/Release/api/s40_schema.obj deleted file mode 100644 index 41c7b5d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s40_schema.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.cp312-win_amd64.exp deleted file mode 100644 index f34f654..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.cp312-win_amd64.lib deleted file mode 100644 index 26e5b16..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.obj b/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.obj deleted file mode 100644 index 3147116..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s41_pipe_risk_probability.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.cp312-win_amd64.exp deleted file mode 100644 index de705ee..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.cp312-win_amd64.lib deleted file mode 100644 index c44020a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.obj b/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.obj deleted file mode 100644 index e726f8f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s42_sensor_placement.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.cp312-win_amd64.exp deleted file mode 100644 index 2da82ea..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.cp312-win_amd64.lib deleted file mode 100644 index 6e2d55f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.obj b/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.obj deleted file mode 100644 index 5f77e7e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s43_burst_locate_result.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.cp312-win_amd64.exp deleted file mode 100644 index 666d6a6..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.cp312-win_amd64.lib deleted file mode 100644 index bd23d71..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.obj b/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.obj deleted file mode 100644 index 7ff9654..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s4_tanks.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.cp312-win_amd64.exp deleted file mode 100644 index 22fc84b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.cp312-win_amd64.lib deleted file mode 100644 index cee7ecc..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.obj b/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.obj deleted file mode 100644 index b7dd790..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s5_pipes.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.cp312-win_amd64.exp deleted file mode 100644 index f8fc427..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.cp312-win_amd64.lib deleted file mode 100644 index fc4085a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.obj b/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.obj deleted file mode 100644 index 5ad34a5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s6_pumps.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s7_valves.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s7_valves.cp312-win_amd64.exp deleted file mode 100644 index c8119c3..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s7_valves.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s7_valves.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s7_valves.cp312-win_amd64.lib deleted file mode 100644 index 6186ff2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s7_valves.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s7_valves.obj b/build/temp.win-amd64-cpython-312/Release/api/s7_valves.obj deleted file mode 100644 index f1583d1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s7_valves.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s8_tags.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s8_tags.cp312-win_amd64.exp deleted file mode 100644 index 5764e82..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s8_tags.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s8_tags.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s8_tags.cp312-win_amd64.lib deleted file mode 100644 index 0975786..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s8_tags.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s8_tags.obj b/build/temp.win-amd64-cpython-312/Release/api/s8_tags.obj deleted file mode 100644 index 487713c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s8_tags.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s9_demands.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/s9_demands.cp312-win_amd64.exp deleted file mode 100644 index 5dfc98d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s9_demands.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s9_demands.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/s9_demands.cp312-win_amd64.lib deleted file mode 100644 index cbee43d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s9_demands.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/s9_demands.obj b/build/temp.win-amd64-cpython-312/Release/api/s9_demands.obj deleted file mode 100644 index 578f20e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/s9_demands.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/sections.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/api/sections.cp312-win_amd64.exp deleted file mode 100644 index 5898a3e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/sections.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/sections.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/api/sections.cp312-win_amd64.lib deleted file mode 100644 index 100aacf..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/sections.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/api/sections.obj b/build/temp.win-amd64-cpython-312/Release/api/sections.obj deleted file mode 100644 index 85ff00c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/api/sections.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/auto_realtime.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/auto_realtime.cp312-win_amd64.exp deleted file mode 100644 index 0fc9406..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/auto_realtime.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/auto_realtime.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/auto_realtime.cp312-win_amd64.lib deleted file mode 100644 index eaef47f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/auto_realtime.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/auto_realtime.obj b/build/temp.win-amd64-cpython-312/Release/auto_realtime.obj deleted file mode 100644 index ec7e112..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/auto_realtime.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.cp312-win_amd64.exp deleted file mode 100644 index dc47968..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.cp312-win_amd64.lib deleted file mode 100644 index 5065e60..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.obj b/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.obj deleted file mode 100644 index ef520f9..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/auto_store_non_realtime_SCADA_data.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/__init__.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/epanet/__init__.cp312-win_amd64.exp deleted file mode 100644 index b650b31..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/__init__.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/__init__.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/epanet/__init__.cp312-win_amd64.lib deleted file mode 100644 index 988a17c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/__init__.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/__init__.obj b/build/temp.win-amd64-cpython-312/Release/epanet/__init__.obj deleted file mode 100644 index 34e2ca1..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/__init__.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/epanet.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/epanet/epanet.cp312-win_amd64.exp deleted file mode 100644 index a929ca7..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/epanet.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/epanet.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/epanet/epanet.cp312-win_amd64.lib deleted file mode 100644 index 46f333f..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/epanet.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/epanet.obj b/build/temp.win-amd64-cpython-312/Release/epanet/epanet.obj deleted file mode 100644 index 3f5e331..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/epanet.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.cp312-win_amd64.exp deleted file mode 100644 index 9a9c2a8..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.cp312-win_amd64.lib deleted file mode 100644 index 34b3e27..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.obj b/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.obj deleted file mode 100644 index 40b4408..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/epanet/epanet2_ec.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_current_status.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/get_current_status.cp312-win_amd64.exp deleted file mode 100644 index c034e36..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_current_status.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_current_status.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/get_current_status.cp312-win_amd64.lib deleted file mode 100644 index a5027e4..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_current_status.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_current_status.obj b/build/temp.win-amd64-cpython-312/Release/get_current_status.obj deleted file mode 100644 index 70c80e8..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_current_status.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.cp312-win_amd64.exp deleted file mode 100644 index 2152f52..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.cp312-win_amd64.lib deleted file mode 100644 index 76693d5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.obj b/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.obj deleted file mode 100644 index c7e63d0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_current_total_Q.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_data.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/get_data.cp312-win_amd64.exp deleted file mode 100644 index c61264d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_data.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_data.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/get_data.cp312-win_amd64.lib deleted file mode 100644 index 032341a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_data.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_data.obj b/build/temp.win-amd64-cpython-312/Release/get_data.obj deleted file mode 100644 index b0bd4b7..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_data.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_hist_data.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/get_hist_data.cp312-win_amd64.exp deleted file mode 100644 index 39d0042..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_hist_data.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_hist_data.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/get_hist_data.cp312-win_amd64.lib deleted file mode 100644 index 145a651..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_hist_data.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_hist_data.obj b/build/temp.win-amd64-cpython-312/Release/get_hist_data.obj deleted file mode 100644 index 41c0408..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_hist_data.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_realValue.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/get_realValue.cp312-win_amd64.exp deleted file mode 100644 index 51854a2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_realValue.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_realValue.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/get_realValue.cp312-win_amd64.lib deleted file mode 100644 index 1b49353..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_realValue.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/get_realValue.obj b/build/temp.win-amd64-cpython-312/Release/get_realValue.obj deleted file mode 100644 index 9447fa2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/get_realValue.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/influxdb_api.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/influxdb_api.cp312-win_amd64.exp deleted file mode 100644 index 21acffe..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/influxdb_api.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/influxdb_api.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/influxdb_api.cp312-win_amd64.lib deleted file mode 100644 index d78b2f2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/influxdb_api.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/influxdb_api.obj b/build/temp.win-amd64-cpython-312/Release/influxdb_api.obj deleted file mode 100644 index aaf92ce..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/influxdb_api.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.cp312-win_amd64.exp deleted file mode 100644 index c2910d2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.cp312-win_amd64.lib deleted file mode 100644 index 00306ae..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.obj b/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.obj deleted file mode 100644 index 88d2c08..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/influxdb_query_SCADA_data.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/main.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/main.cp312-win_amd64.exp deleted file mode 100644 index 3cb9067..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/main.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/main.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/main.cp312-win_amd64.lib deleted file mode 100644 index 29e6e70..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/main.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/main.obj b/build/temp.win-amd64-cpython-312/Release/main.obj deleted file mode 100644 index 38c6aeb..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/main.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/online_Analysis.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/online_Analysis.cp312-win_amd64.exp deleted file mode 100644 index 279464a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/online_Analysis.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/online_Analysis.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/online_Analysis.cp312-win_amd64.lib deleted file mode 100644 index 5373d4d..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/online_Analysis.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/online_Analysis.obj b/build/temp.win-amd64-cpython-312/Release/online_Analysis.obj deleted file mode 100644 index f7e6100..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/online_Analysis.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/run_simlation.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/run_simlation.cp312-win_amd64.exp deleted file mode 100644 index 1610119..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/run_simlation.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/run_simlation.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/run_simlation.cp312-win_amd64.lib deleted file mode 100644 index de4e6e2..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/run_simlation.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/run_simlation.obj b/build/temp.win-amd64-cpython-312/Release/run_simlation.obj deleted file mode 100644 index bf722b9..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/run_simlation.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/run_simulation.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/run_simulation.cp312-win_amd64.exp deleted file mode 100644 index 1d5b240..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/run_simulation.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/run_simulation.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/run_simulation.cp312-win_amd64.lib deleted file mode 100644 index dad31e0..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/run_simulation.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/run_simulation.obj b/build/temp.win-amd64-cpython-312/Release/run_simulation.obj deleted file mode 100644 index 7aae706..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/run_simulation.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/sensitivity.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/sensitivity.cp312-win_amd64.exp deleted file mode 100644 index 2ace013..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/sensitivity.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/sensitivity.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/sensitivity.cp312-win_amd64.lib deleted file mode 100644 index d6b0f5b..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/sensitivity.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/sensitivity.obj b/build/temp.win-amd64-cpython-312/Release/sensitivity.obj deleted file mode 100644 index e9bdce5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/sensitivity.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/sensor_placement.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/sensor_placement.cp312-win_amd64.exp deleted file mode 100644 index 6fa750c..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/sensor_placement.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/sensor_placement.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/sensor_placement.cp312-win_amd64.lib deleted file mode 100644 index a10003a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/sensor_placement.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/sensor_placement.obj b/build/temp.win-amd64-cpython-312/Release/sensor_placement.obj deleted file mode 100644 index c1ef0e5..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/sensor_placement.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/simulation.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/simulation.cp312-win_amd64.exp deleted file mode 100644 index 9aa07a8..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/simulation.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/simulation.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/simulation.cp312-win_amd64.lib deleted file mode 100644 index e4273ad..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/simulation.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/simulation.obj b/build/temp.win-amd64-cpython-312/Release/simulation.obj deleted file mode 100644 index 9d4b952..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/simulation.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/time_api.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/time_api.cp312-win_amd64.exp deleted file mode 100644 index 742223a..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/time_api.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/time_api.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/time_api.cp312-win_amd64.lib deleted file mode 100644 index 2f6e672..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/time_api.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/time_api.obj b/build/temp.win-amd64-cpython-312/Release/time_api.obj deleted file mode 100644 index d918ba4..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/time_api.obj and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/tjnetwork.cp312-win_amd64.exp b/build/temp.win-amd64-cpython-312/Release/tjnetwork.cp312-win_amd64.exp deleted file mode 100644 index 319a40e..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/tjnetwork.cp312-win_amd64.exp and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/tjnetwork.cp312-win_amd64.lib b/build/temp.win-amd64-cpython-312/Release/tjnetwork.cp312-win_amd64.lib deleted file mode 100644 index f29bfbc..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/tjnetwork.cp312-win_amd64.lib and /dev/null differ diff --git a/build/temp.win-amd64-cpython-312/Release/tjnetwork.obj b/build/temp.win-amd64-cpython-312/Release/tjnetwork.obj deleted file mode 100644 index ac7fdfb..0000000 Binary files a/build/temp.win-amd64-cpython-312/Release/tjnetwork.obj and /dev/null differ diff --git a/dev_tools/Redis-7.4.2-Windows-x64-cygwin.zip b/dev_tools/Redis-7.4.2-Windows-x64-cygwin.zip deleted file mode 100644 index 3216673..0000000 Binary files a/dev_tools/Redis-7.4.2-Windows-x64-cygwin.zip and /dev/null differ diff --git a/documents/psycopg3/Pg_Python_API说明.docx b/documents/psycopg3/Pg_Python_API说明.docx deleted file mode 100644 index 01fd28a..0000000 Binary files a/documents/psycopg3/Pg_Python_API说明.docx and /dev/null differ diff --git a/documents/psycopg3/psycopg3 Official document.pdf b/documents/psycopg3/psycopg3 Official document.pdf deleted file mode 100644 index a705706..0000000 Binary files a/documents/psycopg3/psycopg3 Official document.pdf and /dev/null differ diff --git a/documents/psycopg3/psycopg3-all about the love between Python and PostgreSQL.pdf b/documents/psycopg3/psycopg3-all about the love between Python and PostgreSQL.pdf deleted file mode 100644 index e3a2f25..0000000 Binary files a/documents/psycopg3/psycopg3-all about the love between Python and PostgreSQL.pdf and /dev/null differ diff --git a/epanet/__init__.c b/epanet/__init__.c deleted file mode 100644 index 9d7b628..0000000 --- a/epanet/__init__.c +++ /dev/null @@ -1,4829 +0,0 @@ -/* Generated by Cython 3.1.0 */ - -/* BEGIN: Cython Metadata -{ - "distutils": { - "name": "epanet.__init__", - "sources": [ - "epanet\\__init__.py" - ] - }, - "module_name": "epanet.__init__" -} -END: Cython Metadata */ - -#ifndef PY_SSIZE_T_CLEAN -#define PY_SSIZE_T_CLEAN -#endif /* PY_SSIZE_T_CLEAN */ -/* InitLimitedAPI */ -#if defined(Py_LIMITED_API) && !defined(CYTHON_LIMITED_API) - #define CYTHON_LIMITED_API 1 -#endif - -#include "Python.h" -#ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. -#elif PY_VERSION_HEX < 0x03080000 - #error Cython requires Python 3.8+. -#else -#define __PYX_ABI_VERSION "3_1_0" -#define CYTHON_HEX_VERSION 0x030100F0 -#define CYTHON_FUTURE_DIVISION 1 -/* CModulePreamble */ -#include -#ifndef offsetof - #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) -#endif -#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __fastcall - #define __fastcall - #endif -#endif -#ifndef DL_IMPORT - #define DL_IMPORT(t) t -#endif -#ifndef DL_EXPORT - #define DL_EXPORT(t) t -#endif -#define __PYX_COMMA , -#ifndef HAVE_LONG_LONG - #define HAVE_LONG_LONG -#endif -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#ifndef Py_HUGE_VAL - #define Py_HUGE_VAL HUGE_VAL -#endif -#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX -#if defined(GRAALVM_PYTHON) - /* For very preliminary testing purposes. Most variables are set the same as PyPy. - The existence of this section does not imply that anything works or is even tested */ - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 1 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 0 - #undef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #undef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 1 - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #undef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 0 - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #undef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #undef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #undef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 1 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#elif defined(PYPY_VERSION) - #define CYTHON_COMPILING_IN_PYPY 1 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 0 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #ifndef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #endif - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #undef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 1 - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #ifndef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 1 - #endif - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #if PY_VERSION_HEX < 0x03090000 - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 0 - #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #undef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE (PYPY_VERSION_NUM >= 0x07030C00) - #endif - #undef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC (PYPY_VERSION_NUM >= 0x07031100) - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#elif defined(CYTHON_LIMITED_API) - #ifdef Py_LIMITED_API - #undef __PYX_LIMITED_VERSION_HEX - #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API - #endif - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 1 - #define CYTHON_COMPILING_IN_GRAAL 0 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_CLINE_IN_TRACEBACK - #define CYTHON_CLINE_IN_TRACEBACK 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 0 - #undef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 1 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #ifndef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #endif - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #ifndef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 - #endif - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #undef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 0 - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #ifndef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #endif - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #endif - #ifndef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND (__PYX_LIMITED_VERSION_HEX >= 0x030A0000) - #endif - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#else - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 1 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 0 - #ifdef Py_GIL_DISABLED - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 1 - #else - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #endif - #if PY_VERSION_HEX < 0x030A0000 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #elif !defined(CYTHON_USE_TYPE_SLOTS) - #define CYTHON_USE_TYPE_SLOTS 1 - #endif - #ifndef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #endif - #ifndef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 1 - #endif - #ifndef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #elif !defined(CYTHON_USE_PYLIST_INTERNALS) - #define CYTHON_USE_PYLIST_INTERNALS 1 - #endif - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) - #define CYTHON_USE_UNICODE_WRITER 1 - #endif - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #elif !defined(CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS) - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 - #endif - #ifndef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 1 - #endif - #ifndef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 1 - #endif - #ifndef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 1 - #endif - #ifndef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #elif !defined(CYTHON_FAST_GIL) - #define CYTHON_FAST_GIL (PY_VERSION_HEX < 0x030C00A6) - #endif - #ifndef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 1 - #endif - #ifndef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 1 - #endif - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #ifndef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #endif - #ifndef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING (PY_VERSION_HEX >= 0x030d00B1) - #endif - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 1 - #endif - #ifndef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #elif !defined(CYTHON_USE_DICT_VERSIONS) - #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5 && !CYTHON_USE_MODULE_STATE) - #endif - #ifndef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 1 - #endif - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 - #endif - #ifndef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS (!CYTHON_COMPILING_IN_CPYTHON_FREETHREADING) - #endif -#endif -#ifndef CYTHON_FAST_PYCCALL -#define CYTHON_FAST_PYCCALL CYTHON_FAST_PYCALL -#endif -#ifndef CYTHON_VECTORCALL -#if CYTHON_COMPILING_IN_LIMITED_API -#define CYTHON_VECTORCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) -#else -#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) -#endif -#endif -#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) -#if CYTHON_USE_PYLONG_INTERNALS - #undef SHIFT - #undef BASE - #undef MASK - #ifdef SIZEOF_VOID_P - enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; - #endif -#endif -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif -#ifndef __has_cpp_attribute - #define __has_cpp_attribute(x) 0 -#endif -#ifndef CYTHON_RESTRICT - #if defined(__GNUC__) - #define CYTHON_RESTRICT __restrict__ - #elif defined(_MSC_VER) && _MSC_VER >= 1400 - #define CYTHON_RESTRICT __restrict - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_RESTRICT restrict - #else - #define CYTHON_RESTRICT - #endif -#endif -#ifndef CYTHON_UNUSED - #if defined(__cplusplus) - /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 - * but leads to warnings with -pedantic, since it is a C++17 feature */ - #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) - #if __has_cpp_attribute(maybe_unused) - #define CYTHON_UNUSED [[maybe_unused]] - #endif - #endif - #endif -#endif -#ifndef CYTHON_UNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_UNUSED_VAR -# if defined(__cplusplus) - template void CYTHON_UNUSED_VAR( const T& ) { } -# else -# define CYTHON_UNUSED_VAR(x) (void)(x) -# endif -#endif -#ifndef CYTHON_MAYBE_UNUSED_VAR - #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) -#endif -#ifndef CYTHON_NCP_UNUSED -# if CYTHON_COMPILING_IN_CPYTHON -# define CYTHON_NCP_UNUSED -# else -# define CYTHON_NCP_UNUSED CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_USE_CPP_STD_MOVE - #if defined(__cplusplus) && (\ - __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) - #define CYTHON_USE_CPP_STD_MOVE 1 - #else - #define CYTHON_USE_CPP_STD_MOVE 0 - #endif -#endif -#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) -#ifdef _MSC_VER - #ifndef _MSC_STDINT_H_ - #if _MSC_VER < 1300 - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; - #else - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - #endif - #endif - #if _MSC_VER < 1300 - #ifdef _WIN64 - typedef unsigned long long __pyx_uintptr_t; - #else - typedef unsigned int __pyx_uintptr_t; - #endif - #else - #ifdef _WIN64 - typedef unsigned __int64 __pyx_uintptr_t; - #else - typedef unsigned __int32 __pyx_uintptr_t; - #endif - #endif -#else - #include - typedef uintptr_t __pyx_uintptr_t; -#endif -#ifndef CYTHON_FALLTHROUGH - #if defined(__cplusplus) - /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 - * but leads to warnings with -pedantic, since it is a C++17 feature */ - #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) - #if __has_cpp_attribute(fallthrough) - #define CYTHON_FALLTHROUGH [[fallthrough]] - #endif - #endif - #ifndef CYTHON_FALLTHROUGH - #if __has_cpp_attribute(clang::fallthrough) - #define CYTHON_FALLTHROUGH [[clang::fallthrough]] - #elif __has_cpp_attribute(gnu::fallthrough) - #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] - #endif - #endif - #endif - #ifndef CYTHON_FALLTHROUGH - #if __has_attribute(fallthrough) - #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) - #else - #define CYTHON_FALLTHROUGH - #endif - #endif - #if defined(__clang__) && defined(__apple_build_version__) - #if __apple_build_version__ < 7000000 - #undef CYTHON_FALLTHROUGH - #define CYTHON_FALLTHROUGH - #endif - #endif -#endif -#ifndef Py_UNREACHABLE - #define Py_UNREACHABLE() assert(0); abort() -#endif -#ifdef __cplusplus - template - struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; - #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) -#else - #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) -#endif -#if CYTHON_COMPILING_IN_PYPY == 1 - #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) -#else - #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) -#endif -#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) - -/* CInitCode */ -#ifndef CYTHON_INLINE - #if defined(__clang__) - #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) - #elif defined(__GNUC__) - #define CYTHON_INLINE __inline__ - #elif defined(_MSC_VER) - #define CYTHON_INLINE __inline - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_INLINE inline - #else - #define CYTHON_INLINE - #endif -#endif - -/* PythonCompatibility */ -#define __PYX_BUILD_PY_SSIZE_T "n" -#define CYTHON_FORMAT_SSIZE_T "z" -#define __Pyx_BUILTIN_MODULE_NAME "builtins" -#define __Pyx_DefaultClassType PyType_Type -#if CYTHON_COMPILING_IN_LIMITED_API - #ifndef CO_OPTIMIZED - static int CO_OPTIMIZED; - #endif - #ifndef CO_NEWLOCALS - static int CO_NEWLOCALS; - #endif - #ifndef CO_VARARGS - static int CO_VARARGS; - #endif - #ifndef CO_VARKEYWORDS - static int CO_VARKEYWORDS; - #endif - #ifndef CO_ASYNC_GENERATOR - static int CO_ASYNC_GENERATOR; - #endif - #ifndef CO_GENERATOR - static int CO_GENERATOR; - #endif - #ifndef CO_COROUTINE - static int CO_COROUTINE; - #endif -#else - #ifndef CO_COROUTINE - #define CO_COROUTINE 0x80 - #endif - #ifndef CO_ASYNC_GENERATOR - #define CO_ASYNC_GENERATOR 0x200 - #endif -#endif -static int __Pyx_init_co_variables(void); -#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) - #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) -#else - #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) - #define __Pyx_Py_Is(x, y) Py_Is(x, y) -#else - #define __Pyx_Py_Is(x, y) ((x) == (y)) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) - #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) -#else - #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) - #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) -#else - #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) - #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) -#else - #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) -#endif -#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) -#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) -#else - #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) -#endif -#ifndef Py_TPFLAGS_CHECKTYPES - #define Py_TPFLAGS_CHECKTYPES 0 -#endif -#ifndef Py_TPFLAGS_HAVE_INDEX - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#ifndef Py_TPFLAGS_HAVE_NEWBUFFER - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif -#ifndef Py_TPFLAGS_HAVE_FINALIZE - #define Py_TPFLAGS_HAVE_FINALIZE 0 -#endif -#ifndef Py_TPFLAGS_SEQUENCE - #define Py_TPFLAGS_SEQUENCE 0 -#endif -#ifndef Py_TPFLAGS_MAPPING - #define Py_TPFLAGS_MAPPING 0 -#endif -#ifndef METH_STACKLESS - #define METH_STACKLESS 0 -#endif -#ifndef METH_FASTCALL - #ifndef METH_FASTCALL - #define METH_FASTCALL 0x80 - #endif - typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); - typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames); -#else - #if PY_VERSION_HEX >= 0x030d00A4 - # define __Pyx_PyCFunctionFast PyCFunctionFast - # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords - #else - # define __Pyx_PyCFunctionFast _PyCFunctionFast - # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords - #endif -#endif -#if CYTHON_METH_FASTCALL - #define __Pyx_METH_FASTCALL METH_FASTCALL - #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast - #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords -#else - #define __Pyx_METH_FASTCALL METH_VARARGS - #define __Pyx_PyCFunction_FastCall PyCFunction - #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords -#endif -#if CYTHON_VECTORCALL - #define __pyx_vectorcallfunc vectorcallfunc - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET - #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) -#elif CYTHON_BACKPORT_VECTORCALL - typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, - size_t nargsf, PyObject *kwnames); - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) - #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) -#else - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 - #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) -#endif -#if PY_VERSION_HEX >= 0x030900B1 -#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) -#else -#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) -#endif -#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) -#elif !CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) -#endif -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) -static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { - return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; -} -#endif -static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void (*cfunc)(void)) { -#if CYTHON_COMPILING_IN_LIMITED_API - return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; -#else - return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; -#endif -} -#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) -#if __PYX_LIMITED_VERSION_HEX < 0x03090000 - #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) - typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); -#else - #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) - #define __Pyx_PyCMethod PyCMethod -#endif -#ifndef METH_METHOD - #define METH_METHOD 0x200 -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) - #define PyObject_Malloc(s) PyMem_Malloc(s) - #define PyObject_Free(p) PyMem_Free(p) - #define PyObject_Realloc(p) PyMem_Realloc(p) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) -#elif CYTHON_COMPILING_IN_GRAAL - #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) _PyFrame_SetLineNumber((frame), (lineno)) -#else - #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyThreadState_Current PyThreadState_Get() -#elif !CYTHON_FAST_THREAD_STATE - #define __Pyx_PyThreadState_Current PyThreadState_GET() -#elif PY_VERSION_HEX >= 0x030d00A1 - #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() -#else - #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() -#endif -#if CYTHON_USE_MODULE_STATE -static CYTHON_INLINE void *__Pyx__PyModule_GetState(PyObject *op) -{ - void *result; - result = PyModule_GetState(op); - if (!result) - Py_FatalError("Couldn't find the module state"); - return result; -} -#define __Pyx_PyModule_GetState(o) (__pyx_mstatetype *)__Pyx__PyModule_GetState(o) -#else -#define __Pyx_PyModule_GetState(op) ((void)op,__pyx_mstate_global) -#endif -#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE((PyObject *) obj), name, func_ctype) -#define __Pyx_PyObject_TryGetSlot(obj, name, func_ctype) __Pyx_PyType_TryGetSlot(Py_TYPE(obj), name, func_ctype) -#define __Pyx_PyObject_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(Py_TYPE(obj), sub, name, func_ctype) -#define __Pyx_PyObject_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSubSlot(Py_TYPE(obj), sub, name, func_ctype) -#if CYTHON_USE_TYPE_SLOTS - #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) - #define __Pyx_PyType_TryGetSlot(type, name, func_ctype) __Pyx_PyType_GetSlot(type, name, func_ctype) - #define __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) (((type)->sub) ? ((type)->sub->name) : NULL) - #define __Pyx_PyType_TryGetSubSlot(type, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) -#else - #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) - #define __Pyx_PyType_TryGetSlot(type, name, func_ctype)\ - ((__PYX_LIMITED_VERSION_HEX >= 0x030A0000 ||\ - (PyType_GetFlags(type) & Py_TPFLAGS_HEAPTYPE) || __Pyx_get_runtime_version() >= 0x030A0000) ?\ - __Pyx_PyType_GetSlot(type, name, func_ctype) : NULL) - #define __Pyx_PyType_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSlot(obj, name, func_ctype) - #define __Pyx_PyType_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSlot(obj, name, func_ctype) -#endif -#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) -#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) -#else -#define __Pyx_PyDict_NewPresized(n) PyDict_New() -#endif -#define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) -#define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) -#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_UNICODE_INTERNALS -#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) -static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { - PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); - if (res == NULL) PyErr_Clear(); - return res; -} -#elif !CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000 -#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError -#define __Pyx_PyDict_GetItemStr PyDict_GetItem -#else -static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { -#if CYTHON_COMPILING_IN_PYPY - return PyDict_GetItem(dict, name); -#else - PyDictEntry *ep; - PyDictObject *mp = (PyDictObject*) dict; - long hash = ((PyStringObject *) name)->ob_shash; - assert(hash != -1); - ep = (mp->ma_lookup)(mp, name, hash); - if (ep == NULL) { - return NULL; - } - return ep->me_value; -#endif -} -#define __Pyx_PyDict_GetItemStr PyDict_GetItem -#endif -#if CYTHON_USE_TYPE_SLOTS - #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) - #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) -#else - #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) - #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) -#endif -#define __Pyx_PyObject_GetIterNextFunc(iterator) __Pyx_PyObject_GetSlot(iterator, tp_iternext, iternextfunc) -#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 -#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ - PyTypeObject *type = Py_TYPE((PyObject*)obj);\ - assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ - PyObject_GC_Del(obj);\ - Py_DECREF(type);\ -} -#else -#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyUnicode_READY(op) (0) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) - #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) - #define __Pyx_PyUnicode_DATA(u) ((void*)u) - #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) -#else - #if PY_VERSION_HEX >= 0x030C0000 - #define __Pyx_PyUnicode_READY(op) (0) - #else - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) - #endif - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) - #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) - #if PY_VERSION_HEX >= 0x030C0000 - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) - #else - #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) - #endif - #endif -#endif -#if CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) -#else - #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ - PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) -#endif -#if CYTHON_COMPILING_IN_PYPY - #if !defined(PyUnicode_DecodeUnicodeEscape) - #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) - #endif - #if !defined(PyUnicode_Contains) - #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) - #endif - #if !defined(PyByteArray_Check) - #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) - #endif - #if !defined(PyObject_Format) - #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) - #endif -#endif -#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) -#if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_PySequence_ListKeepNew(obj)\ - (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) -#else - #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) -#endif -#ifndef PySet_CheckExact - #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) -#endif -#if PY_VERSION_HEX >= 0x030900A4 - #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -#else - #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS || !CYTHON_ASSUME_SAFE_MACROS - #if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - #define __Pyx_PyList_GetItemRef(o, i) PyList_GetItemRef(o, i) - #else - #define __Pyx_PyList_GetItemRef(o, i) PySequence_GetItem(o, i) - #endif -#else - #define __Pyx_PyList_GetItemRef(o, i) __Pyx_NewRef(PyList_GET_ITEM(o, i)) -#endif -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 -#define __Pyx_PyDict_GetItemRef(dict, key, result) PyDict_GetItemRef(dict, key, result) -#elif CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS -static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { - *result = PyObject_GetItem(dict, key); - if (*result == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - return 0; - } - return -1; - } - return 1; -} -#else -static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { - *result = PyDict_GetItemWithError(dict, key); - if (*result == NULL) { - return PyErr_Occurred() ? -1 : 0; - } - Py_INCREF(*result); - return 1; -} -#endif -#if defined(CYTHON_DEBUG_VISIT_CONST) && CYTHON_DEBUG_VISIT_CONST - #define __Pyx_VISIT_CONST(obj) Py_VISIT(obj) -#else - #define __Pyx_VISIT_CONST(obj) -#endif -#if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) - #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GET_ITEM(o, i) - #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) - #define __Pyx_PyList_GET_ITEM(o, i) PyList_GET_ITEM(o, i) -#else - #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) - #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) - #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) - #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GetItem(o, i) - #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) - #define __Pyx_PyList_GET_ITEM(o, i) PyList_GetItem(o, i) -#endif -#if CYTHON_ASSUME_SAFE_SIZE - #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) - #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) - #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) - #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) - #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) - #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GET_LENGTH(o) -#else - #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) - #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) - #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) - #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) - #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) - #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GetLength(o) -#endif -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) -#else - static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { - PyObject *module = PyImport_AddModule(name); - Py_XINCREF(module); - return module; - } -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_InternFromString) - #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) -#endif -#define __Pyx_PyLong_FromHash_t PyLong_FromSsize_t -#define __Pyx_PyLong_AsHash_t __Pyx_PyIndex_AsSsize_t -#if __PYX_LIMITED_VERSION_HEX >= 0x030A0000 - #define __Pyx_PySendResult PySendResult -#else - typedef enum { - PYGEN_RETURN = 0, - PYGEN_ERROR = -1, - PYGEN_NEXT = 1, - } __Pyx_PySendResult; -#endif -#if CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX < 0x030A00A3 - typedef __Pyx_PySendResult (*__Pyx_pyiter_sendfunc)(PyObject *iter, PyObject *value, PyObject **result); -#else - #define __Pyx_pyiter_sendfunc sendfunc -#endif -#if !CYTHON_USE_AM_SEND -#define __PYX_HAS_PY_AM_SEND 0 -#elif __PYX_LIMITED_VERSION_HEX >= 0x030A0000 -#define __PYX_HAS_PY_AM_SEND 1 -#else -#define __PYX_HAS_PY_AM_SEND 2 // our own backported implementation -#endif -#if __PYX_HAS_PY_AM_SEND < 2 - #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods -#else - typedef struct { - unaryfunc am_await; - unaryfunc am_aiter; - unaryfunc am_anext; - __Pyx_pyiter_sendfunc am_send; - } __Pyx_PyAsyncMethodsStruct; - #define __Pyx_SlotTpAsAsync(s) ((PyAsyncMethods*)(s)) -#endif -#if CYTHON_USE_AM_SEND && PY_VERSION_HEX < 0x030A00F0 - #define __Pyx_TPFLAGS_HAVE_AM_SEND (1UL << 21) -#else - #define __Pyx_TPFLAGS_HAVE_AM_SEND (0) -#endif -#if PY_VERSION_HEX >= 0x03090000 -#define __Pyx_PyInterpreterState_Get() PyInterpreterState_Get() -#else -#define __Pyx_PyInterpreterState_Get() PyThreadState_Get()->interp -#endif -#if CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030A0000 -#ifdef __cplusplus -extern "C" -#endif -PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize); -#endif -#if CYTHON_COMPILING_IN_LIMITED_API -static int __Pyx_init_co_variable(PyObject *inspect, const char* name, int *write_to) { - int value; - PyObject *py_value = PyObject_GetAttrString(inspect, name); - if (!py_value) return 0; - value = (int) PyLong_AsLong(py_value); - Py_DECREF(py_value); - *write_to = value; - return value != -1 || !PyErr_Occurred(); -} -static int __Pyx_init_co_variables(void) { - PyObject *inspect; - int result; - inspect = PyImport_ImportModule("inspect"); - result = -#if !defined(CO_OPTIMIZED) - __Pyx_init_co_variable(inspect, "CO_OPTIMIZED", &CO_OPTIMIZED) && -#endif -#if !defined(CO_NEWLOCALS) - __Pyx_init_co_variable(inspect, "CO_NEWLOCALS", &CO_NEWLOCALS) && -#endif -#if !defined(CO_VARARGS) - __Pyx_init_co_variable(inspect, "CO_VARARGS", &CO_VARARGS) && -#endif -#if !defined(CO_VARKEYWORDS) - __Pyx_init_co_variable(inspect, "CO_VARKEYWORDS", &CO_VARKEYWORDS) && -#endif -#if !defined(CO_ASYNC_GENERATOR) - __Pyx_init_co_variable(inspect, "CO_ASYNC_GENERATOR", &CO_ASYNC_GENERATOR) && -#endif -#if !defined(CO_GENERATOR) - __Pyx_init_co_variable(inspect, "CO_GENERATOR", &CO_GENERATOR) && -#endif -#if !defined(CO_COROUTINE) - __Pyx_init_co_variable(inspect, "CO_COROUTINE", &CO_COROUTINE) && -#endif - 1; - Py_DECREF(inspect); - return result ? 0 : -1; -} -#else -static int __Pyx_init_co_variables(void) { - return 0; // It's a limited API-only feature -} -#endif - -/* MathInitCode */ -#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) - #ifndef _USE_MATH_DEFINES - #define _USE_MATH_DEFINES - #endif -#endif -#include -#ifdef NAN -#define __PYX_NAN() ((float) NAN) -#else -static CYTHON_INLINE float __PYX_NAN() { - float value; - memset(&value, 0xFF, sizeof(value)); - return value; -} -#endif -#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) -#define __Pyx_truncl trunc -#else -#define __Pyx_truncl truncl -#endif - -#ifndef CYTHON_CLINE_IN_TRACEBACK_RUNTIME -#define CYTHON_CLINE_IN_TRACEBACK_RUNTIME 0 -#endif -#ifndef CYTHON_CLINE_IN_TRACEBACK -#define CYTHON_CLINE_IN_TRACEBACK CYTHON_CLINE_IN_TRACEBACK_RUNTIME -#endif -#if CYTHON_CLINE_IN_TRACEBACK -#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; __pyx_clineno = __LINE__; (void) __pyx_clineno; } -#else -#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; (void) __pyx_clineno; } -#endif -#define __PYX_ERR(f_index, lineno, Ln_error) \ - { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - -#ifdef CYTHON_EXTERN_C - #undef __PYX_EXTERN_C - #define __PYX_EXTERN_C CYTHON_EXTERN_C -#elif defined(__PYX_EXTERN_C) - #ifdef _MSC_VER - #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") - #else - #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. - #endif -#else - #ifdef __cplusplus - #define __PYX_EXTERN_C extern "C" - #else - #define __PYX_EXTERN_C extern - #endif -#endif - -#define __PYX_HAVE__epanet -#define __PYX_HAVE_API__epanet -/* Early includes */ -#ifdef _OPENMP -#include -#endif /* _OPENMP */ - -#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) -#define CYTHON_WITHOUT_ASSERTIONS -#endif - -#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 -#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 -#define __PYX_DEFAULT_STRING_ENCODING "" -#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString -#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize -#define __Pyx_uchar_cast(c) ((unsigned char)c) -#define __Pyx_long_cast(x) ((long)x) -#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ - (sizeof(type) < sizeof(Py_ssize_t)) ||\ - (sizeof(type) > sizeof(Py_ssize_t) &&\ - likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX) &&\ - (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ - v == (type)PY_SSIZE_T_MIN))) ||\ - (sizeof(type) == sizeof(Py_ssize_t) &&\ - (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX))) ) -static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { - return (size_t) i < (size_t) limit; -} -#if defined (__cplusplus) && __cplusplus >= 201103L - #include - #define __Pyx_sst_abs(value) std::abs(value) -#elif SIZEOF_INT >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) abs(value) -#elif SIZEOF_LONG >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) labs(value) -#elif defined (_MSC_VER) - #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) -#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define __Pyx_sst_abs(value) llabs(value) -#elif defined (__GNUC__) - #define __Pyx_sst_abs(value) __builtin_llabs(value) -#else - #define __Pyx_sst_abs(value) ((value<0) ? -value : value) -#endif -static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); -static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); -#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) -#define __Pyx_PyBytes_FromString PyBytes_FromString -#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); -#if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyByteArray_AsString(s) PyByteArray_AS_STRING(s) -#else - #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AsString(s)) - #define __Pyx_PyByteArray_AsString(s) PyByteArray_AsString(s) -#endif -#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) -#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) -#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) -#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) -#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) -#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode -static CYTHON_INLINE PyObject *__Pyx_NewRef(PyObject *obj) { -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_NewRef) - return Py_NewRef(obj); -#else - Py_INCREF(obj); - return obj; -#endif -} -static CYTHON_INLINE PyObject *__Pyx_XNewRef(PyObject *obj) { -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_XNewRef) - return Py_XNewRef(obj); -#else - Py_XINCREF(obj); - return obj; -#endif -} -static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b); -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x); -#define __Pyx_PySequence_Tuple(obj)\ - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); -static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t); -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); -#if CYTHON_ASSUME_SAFE_MACROS -#define __Pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) -#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AS_DOUBLE(x) -#else -#define __Pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) -#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AsDouble(x) -#endif -#define __Pyx_PyFloat_AsFloat(x) ((float) __Pyx_PyFloat_AsDouble(x)) -#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) -#if CYTHON_USE_PYLONG_INTERNALS - #if PY_VERSION_HEX >= 0x030C00A7 - #ifndef _PyLong_SIGN_MASK - #define _PyLong_SIGN_MASK 3 - #endif - #ifndef _PyLong_NON_SIZE_BITS - #define _PyLong_NON_SIZE_BITS 3 - #endif - #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) - #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) - #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) - #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) - #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) - #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) - #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) - #define __Pyx_PyLong_SignedDigitCount(x)\ - ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) - #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) - #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) - #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) - #else - #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) - #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) - #endif - typedef Py_ssize_t __Pyx_compact_pylong; - typedef size_t __Pyx_compact_upylong; - #else - #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) - #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) - #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) - #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) - #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) - #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) - #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) - #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) - #define __Pyx_PyLong_CompactValue(x)\ - ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) - typedef sdigit __Pyx_compact_pylong; - typedef digit __Pyx_compact_upylong; - #endif - #if PY_VERSION_HEX >= 0x030C00A5 - #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) - #else - #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) - #endif -#endif -#if __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) -#elif __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeASCII(c_str, size, NULL) -#else - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) -#endif - - -/* Test for GCC > 2.95 */ -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) - #define likely(x) __builtin_expect(!!(x), 1) - #define unlikely(x) __builtin_expect(!!(x), 0) -#else /* !__GNUC__ or GCC < 2.95 */ - #define likely(x) (x) - #define unlikely(x) (x) -#endif /* __GNUC__ */ -/* PretendToInitialize */ -#ifdef __cplusplus -#include -template -static void __Pyx_pretend_to_initialize(T* ptr) { -#if __cplusplus > 201103L - if ((std::is_trivially_default_constructible::value)) -#endif - *ptr = T(); - (void)ptr; -} -#else -static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } -#endif - - -#if !CYTHON_USE_MODULE_STATE -static PyObject *__pyx_m = NULL; -#endif -static int __pyx_lineno; -static int __pyx_clineno = 0; -static const char * const __pyx_cfilenm = __FILE__; -static const char *__pyx_filename; - -/* #### Code section: filename_table ### */ - -static const char* const __pyx_f[] = { - "epanet/__init__.py", -}; -/* #### Code section: utility_code_proto_before_types ### */ -/* CriticalSections.proto */ -#if !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING -#define __Pyx_PyCriticalSection void* -#define __Pyx_PyCriticalSection2 void* -#define __Pyx_PyCriticalSection_Begin1(cs, arg) (void)cs -#define __Pyx_PyCriticalSection_Begin2(cs, arg1, arg2) (void)cs -#define __Pyx_PyCriticalSection_End1(cs) -#define __Pyx_PyCriticalSection_End2(cs) -#else -#define __Pyx_PyCriticalSection PyCriticalSection -#define __Pyx_PyCriticalSection2 PyCriticalSection2 -#define __Pyx_PyCriticalSection_Begin1 PyCriticalSection_Begin -#define __Pyx_PyCriticalSection_Begin2 PyCriticalSection2_Begin -#define __Pyx_PyCriticalSection_End1 PyCriticalSection_End -#define __Pyx_PyCriticalSection_End2 PyCriticalSection2_End -#endif -#if PY_VERSION_HEX < 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_BEGIN_CRITICAL_SECTION(o) { -#define __Pyx_END_CRITICAL_SECTION() } -#else -#define __Pyx_BEGIN_CRITICAL_SECTION Py_BEGIN_CRITICAL_SECTION -#define __Pyx_END_CRITICAL_SECTION Py_END_CRITICAL_SECTION -#endif - -/* Atomics.proto */ -#include -#ifndef CYTHON_ATOMICS - #define CYTHON_ATOMICS 1 -#endif -#define __PYX_CYTHON_ATOMICS_ENABLED() CYTHON_ATOMICS -#define __PYX_GET_CYTHON_COMPILING_IN_CPYTHON_FREETHREADING() CYTHON_COMPILING_IN_CPYTHON_FREETHREADING -#define __pyx_atomic_int_type int -#define __pyx_nonatomic_int_type int -#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ - (__STDC_VERSION__ >= 201112L) &&\ - !defined(__STDC_NO_ATOMICS__)) - #include -#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ - (__cplusplus >= 201103L) ||\ - (defined(_MSC_VER) && _MSC_VER >= 1700))) - #include -#endif -#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ - (__STDC_VERSION__ >= 201112L) &&\ - !defined(__STDC_NO_ATOMICS__) &&\ - ATOMIC_INT_LOCK_FREE == 2) - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type atomic_int - #define __pyx_atomic_ptr_type atomic_uintptr_t - #define __pyx_nonatomic_ptr_type uintptr_t - #define __pyx_atomic_incr_relaxed(value) atomic_fetch_add_explicit(value, 1, memory_order_relaxed) - #define __pyx_atomic_incr_acq_rel(value) atomic_fetch_add_explicit(value, 1, memory_order_acq_rel) - #define __pyx_atomic_decr_acq_rel(value) atomic_fetch_sub_explicit(value, 1, memory_order_acq_rel) - #define __pyx_atomic_sub(value, arg) atomic_fetch_sub(value, arg) - #define __pyx_atomic_int_cmp_exchange(value, expected, desired) atomic_compare_exchange_strong(value, expected, desired) - #define __pyx_atomic_load(value) atomic_load(value) - #define __pyx_atomic_store(value, new_value) atomic_store(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) atomic_load_explicit(value, memory_order_relaxed) - #define __pyx_atomic_pointer_load_acquire(value) atomic_load_explicit(value, memory_order_acquire) - #define __pyx_atomic_pointer_exchange(value, new_value) atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) - #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) - #pragma message ("Using standard C atomics") - #elif defined(__PYX_DEBUG_ATOMICS) - #warning "Using standard C atomics" - #endif -#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ - (__cplusplus >= 201103L) ||\ -\ - (defined(_MSC_VER) && _MSC_VER >= 1700)) &&\ - ATOMIC_INT_LOCK_FREE == 2) - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type std::atomic_int - #define __pyx_atomic_ptr_type std::atomic_uintptr_t - #define __pyx_nonatomic_ptr_type uintptr_t - #define __pyx_atomic_incr_relaxed(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_relaxed) - #define __pyx_atomic_incr_acq_rel(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_acq_rel) - #define __pyx_atomic_decr_acq_rel(value) std::atomic_fetch_sub_explicit(value, 1, std::memory_order_acq_rel) - #define __pyx_atomic_sub(value, arg) std::atomic_fetch_sub(value, arg) - #define __pyx_atomic_int_cmp_exchange(value, expected, desired) std::atomic_compare_exchange_strong(value, expected, desired) - #define __pyx_atomic_load(value) std::atomic_load(value) - #define __pyx_atomic_store(value, new_value) std::atomic_store(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) std::atomic_load_explicit(value, std::memory_order_relaxed) - #define __pyx_atomic_pointer_load_acquire(value) std::atomic_load_explicit(value, std::memory_order_acquire) - #define __pyx_atomic_pointer_exchange(value, new_value) std::atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) - #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) - #pragma message ("Using standard C++ atomics") - #elif defined(__PYX_DEBUG_ATOMICS) - #warning "Using standard C++ atomics" - #endif -#elif CYTHON_ATOMICS && (__GNUC__ >= 5 || (__GNUC__ == 4 &&\ - (__GNUC_MINOR__ > 1 ||\ - (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 2)))) - #define __pyx_atomic_ptr_type void* - #define __pyx_atomic_incr_relaxed(value) __sync_fetch_and_add(value, 1) - #define __pyx_atomic_incr_acq_rel(value) __sync_fetch_and_add(value, 1) - #define __pyx_atomic_decr_acq_rel(value) __sync_fetch_and_sub(value, 1) - #define __pyx_atomic_sub(value, arg) __sync_fetch_and_sub(value, arg) - static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { - __pyx_nonatomic_int_type old = __sync_val_compare_and_swap(value, *expected, desired); - int result = old == *expected; - *expected = old; - return result; - } - #define __pyx_atomic_load(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_store(value, new_value) __sync_lock_test_and_set(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_pointer_load_acquire(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_pointer_exchange(value, new_value) __sync_lock_test_and_set(value, (__pyx_atomic_ptr_type)new_value) - #ifdef __PYX_DEBUG_ATOMICS - #warning "Using GNU atomics" - #endif -#elif CYTHON_ATOMICS && defined(_MSC_VER) - #include - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type long - #define __pyx_atomic_ptr_type void* - #undef __pyx_nonatomic_int_type - #define __pyx_nonatomic_int_type long - #pragma intrinsic (_InterlockedExchangeAdd, _InterlockedExchange, _InterlockedCompareExchange, _InterlockedCompareExchangePointer, _InterlockedExchangePointer) - #define __pyx_atomic_incr_relaxed(value) _InterlockedExchangeAdd(value, 1) - #define __pyx_atomic_incr_acq_rel(value) _InterlockedExchangeAdd(value, 1) - #define __pyx_atomic_decr_acq_rel(value) _InterlockedExchangeAdd(value, -1) - #define __pyx_atomic_sub(value, arg) _InterlockedExchangeAdd(value, -arg) - static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { - __pyx_nonatomic_int_type old = _InterlockedCompareExchange(value, desired, *expected); - int result = old == *expected; - *expected = old; - return result; - } - #define __pyx_atomic_load(value) _InterlockedExchangeAdd(value, 0) - #define __pyx_atomic_store(value, new_value) _InterlockedExchange(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) *(void * volatile *)value - #define __pyx_atomic_pointer_load_acquire(value) _InterlockedCompareExchangePointer(value, 0, 0) - #define __pyx_atomic_pointer_exchange(value, new_value) _InterlockedExchangePointer(value, (__pyx_atomic_ptr_type)new_value) - #ifdef __PYX_DEBUG_ATOMICS - #pragma message ("Using MSVC atomics") - #endif -#else - #undef CYTHON_ATOMICS - #define CYTHON_ATOMICS 0 - #ifdef __PYX_DEBUG_ATOMICS - #warning "Not using atomics" - #endif -#endif -#if CYTHON_ATOMICS - #define __pyx_add_acquisition_count(memview)\ - __pyx_atomic_incr_relaxed(__pyx_get_slice_count_pointer(memview)) - #define __pyx_sub_acquisition_count(memview)\ - __pyx_atomic_decr_acq_rel(__pyx_get_slice_count_pointer(memview)) -#else - #define __pyx_add_acquisition_count(memview)\ - __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) - #define __pyx_sub_acquisition_count(memview)\ - __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) -#endif - -/* #### Code section: numeric_typedefs ### */ -/* #### Code section: complex_type_declarations ### */ -/* #### Code section: type_declarations ### */ - -/*--- Type declarations ---*/ -/* #### Code section: utility_code_proto ### */ - -/* --- Runtime support code (head) --- */ -/* Refnanny.proto */ -#ifndef CYTHON_REFNANNY - #define CYTHON_REFNANNY 0 -#endif -#if CYTHON_REFNANNY - typedef struct { - void (*INCREF)(void*, PyObject*, Py_ssize_t); - void (*DECREF)(void*, PyObject*, Py_ssize_t); - void (*GOTREF)(void*, PyObject*, Py_ssize_t); - void (*GIVEREF)(void*, PyObject*, Py_ssize_t); - void* (*SetupContext)(const char*, Py_ssize_t, const char*); - void (*FinishContext)(void**); - } __Pyx_RefNannyAPIStruct; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); - #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; - #define __Pyx_RefNannySetupContext(name, acquire_gil)\ - if (acquire_gil) {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ - PyGILState_Release(__pyx_gilstate_save);\ - } else {\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ - } - #define __Pyx_RefNannyFinishContextNogil() {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __Pyx_RefNannyFinishContext();\ - PyGILState_Release(__pyx_gilstate_save);\ - } - #define __Pyx_RefNannyFinishContextNogil() {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __Pyx_RefNannyFinishContext();\ - PyGILState_Release(__pyx_gilstate_save);\ - } - #define __Pyx_RefNannyFinishContext()\ - __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) - #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) - #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) - #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) -#else - #define __Pyx_RefNannyDeclarations - #define __Pyx_RefNannySetupContext(name, acquire_gil) - #define __Pyx_RefNannyFinishContextNogil() - #define __Pyx_RefNannyFinishContext() - #define __Pyx_INCREF(r) Py_INCREF(r) - #define __Pyx_DECREF(r) Py_DECREF(r) - #define __Pyx_GOTREF(r) - #define __Pyx_GIVEREF(r) - #define __Pyx_XINCREF(r) Py_XINCREF(r) - #define __Pyx_XDECREF(r) Py_XDECREF(r) - #define __Pyx_XGOTREF(r) - #define __Pyx_XGIVEREF(r) -#endif -#define __Pyx_Py_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; Py_XDECREF(tmp);\ - } while (0) -#define __Pyx_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_XDECREF(tmp);\ - } while (0) -#define __Pyx_DECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_DECREF(tmp);\ - } while (0) -#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) -#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) - -/* SetPackagePathFromImportLib.proto */ -#if !CYTHON_PEP489_MULTI_PHASE_INIT -static int __Pyx_SetPackagePathFromImportLib(PyObject *module_name); -#else -#define __Pyx_SetPackagePathFromImportLib(a) 0 -#endif - -/* ListPack.proto */ -static PyObject *__Pyx_PyList_Pack(Py_ssize_t n, ...); - -/* PyObjectGetAttrStr.proto */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); -#else -#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) -#endif - -/* IncludeStringH.proto */ -#include - -/* Import.proto */ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); - -/* ImportFrom.proto */ -static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); - -/* PyDictVersioning.proto */ -#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS -#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) -#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ - (version_var) = __PYX_GET_DICT_VERSION(dict);\ - (cache_var) = (value); -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ - static PY_UINT64_T __pyx_dict_version = 0;\ - static PyObject *__pyx_dict_cached_value = NULL;\ - if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ - (VAR) = __pyx_dict_cached_value;\ - } else {\ - (VAR) = __pyx_dict_cached_value = (LOOKUP);\ - __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ - }\ -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); -#else -#define __PYX_GET_DICT_VERSION(dict) (0) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); -#endif - -/* PyErrExceptionMatches.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) -static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); -#else -#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) -#endif - -/* PyThreadStateGet.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; -#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; -#if PY_VERSION_HEX >= 0x030C00A6 -#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) -#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) -#else -#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) -#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) -#endif -#else -#define __Pyx_PyThreadState_declare -#define __Pyx_PyThreadState_assign -#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) -#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() -#endif - -/* PyErrFetchRestore.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) -#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 -#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) -#else -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#endif -#else -#define __Pyx_PyErr_Clear() PyErr_Clear() -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) -#endif - -/* PyObjectGetAttrStrNoError.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); - -/* CLineInTraceback.proto */ -#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME -static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); -#else -#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) -#endif - -/* CodeObjectCache.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API -typedef PyObject __Pyx_CachedCodeObjectType; -#else -typedef PyCodeObject __Pyx_CachedCodeObjectType; -#endif -typedef struct { - __Pyx_CachedCodeObjectType* code_object; - int code_line; -} __Pyx_CodeObjectCacheEntry; -struct __Pyx_CodeObjectCache { - int count; - int max_count; - __Pyx_CodeObjectCacheEntry* entries; - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_int_type accessor_count; - #endif -}; -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); -static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line); -static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object); - -/* AddTraceback.proto */ -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - -/* FormatTypeName.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API -typedef PyObject *__Pyx_TypeName; -#define __Pyx_FMT_TYPENAME "%U" -#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 -#define __Pyx_PyType_GetFullyQualifiedName PyType_GetFullyQualifiedName -#else -static __Pyx_TypeName __Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp); -#endif -#else // !LIMITED_API -typedef const char *__Pyx_TypeName; -#define __Pyx_FMT_TYPENAME "%.200s" -#define __Pyx_PyType_GetFullyQualifiedName(tp) ((tp)->tp_name) -#define __Pyx_DECREF_TypeName(obj) -#endif - -/* GCCDiagnostics.proto */ -#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define __Pyx_HAS_GCC_DIAGNOSTIC -#endif - -/* PyFunctionFastCall.proto */ -#if CYTHON_FAST_PYCALL -#if !CYTHON_VECTORCALL -#define __Pyx_PyFunction_FastCall(func, args, nargs)\ - __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs); -#endif -#define __Pyx_BUILD_ASSERT_EXPR(cond)\ - (sizeof(char [1 - 2*!(cond)]) - 1) -#ifndef Py_MEMBER_SIZE -#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) -#endif -#if !CYTHON_VECTORCALL -#if PY_VERSION_HEX >= 0x03080000 - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets() - #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) -#else - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ - ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -#endif -#endif -#endif - -/* PyObjectCall.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); -#else -#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) -#endif - -/* PyObjectCallMethO.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); -#endif - -/* PyObjectFastCall.proto */ -#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) -static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs); - -/* PyObjectVectorCallKwBuilder.proto */ -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); -#if CYTHON_VECTORCALL -#if PY_VERSION_HEX >= 0x03090000 -#define __Pyx_Object_Vectorcall_CallFromBuilder PyObject_Vectorcall -#else -#define __Pyx_Object_Vectorcall_CallFromBuilder _PyObject_Vectorcall -#endif -#define __Pyx_MakeVectorcallBuilderKwds(n) PyTuple_New(n) -static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); -static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n); -#else -#define __Pyx_Object_Vectorcall_CallFromBuilder __Pyx_PyObject_FastCallDict -#define __Pyx_MakeVectorcallBuilderKwds(n) __Pyx_PyDict_NewPresized(n) -#define __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n) PyDict_SetItem(builder, key, value) -#define __Pyx_VectorcallBuilder_AddArgStr(key, value, builder, args, n) PyDict_SetItemString(builder, key, value) -#endif - -/* CIntToPy.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value); - -/* CIntFromPy.proto */ -static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *); - -/* CIntFromPy.proto */ -static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *); - -/* FastTypeChecks.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); -static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); -#else -#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) -#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) -#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2) { - return PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2); -} -#endif -#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) -#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) -#ifdef PyExceptionInstance_Check - #define __Pyx_PyBaseException_Check(obj) PyExceptionInstance_Check(obj) -#else - #define __Pyx_PyBaseException_Check(obj) __Pyx_TypeCheck(obj, PyExc_BaseException) -#endif - -/* GetRuntimeVersion.proto */ -static unsigned long __Pyx_get_runtime_version(void); - -/* CheckBinaryVersion.proto */ -static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); - -/* MultiPhaseInitModuleState.proto */ -#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE -static PyObject *__Pyx_State_FindModule(void*); -static int __Pyx_State_AddModule(PyObject* module, void*); -static int __Pyx_State_RemoveModule(void*); -#elif CYTHON_USE_MODULE_STATE -#define __Pyx_State_FindModule PyState_FindModule -#define __Pyx_State_AddModule PyState_AddModule -#define __Pyx_State_RemoveModule PyState_RemoveModule -#endif - -/* #### Code section: module_declarations ### */ -/* CythonABIVersion.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API - #if CYTHON_METH_FASTCALL - #define __PYX_FASTCALL_ABI_SUFFIX "_fastcall" - #else - #define __PYX_FASTCALL_ABI_SUFFIX - #endif - #define __PYX_LIMITED_ABI_SUFFIX "limited" __PYX_FASTCALL_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX -#else - #define __PYX_LIMITED_ABI_SUFFIX -#endif -#if __PYX_HAS_PY_AM_SEND == 1 - #define __PYX_AM_SEND_ABI_SUFFIX -#elif __PYX_HAS_PY_AM_SEND == 2 - #define __PYX_AM_SEND_ABI_SUFFIX "amsendbackport" -#else - #define __PYX_AM_SEND_ABI_SUFFIX "noamsend" -#endif -#ifndef __PYX_MONITORING_ABI_SUFFIX - #define __PYX_MONITORING_ABI_SUFFIX -#endif -#if CYTHON_USE_TP_FINALIZE - #define __PYX_TP_FINALIZE_ABI_SUFFIX -#else - #define __PYX_TP_FINALIZE_ABI_SUFFIX "nofinalize" -#endif -#if CYTHON_USE_FREELISTS || !defined(__Pyx_AsyncGen_USED) - #define __PYX_FREELISTS_ABI_SUFFIX -#else - #define __PYX_FREELISTS_ABI_SUFFIX "nofreelists" -#endif -#define CYTHON_ABI __PYX_ABI_VERSION __PYX_LIMITED_ABI_SUFFIX __PYX_MONITORING_ABI_SUFFIX __PYX_TP_FINALIZE_ABI_SUFFIX __PYX_FREELISTS_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX -#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI -#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." - - -/* Module declarations from "epanet" */ -/* #### Code section: typeinfo ### */ -/* #### Code section: before_global_var ### */ -#define __Pyx_MODULE_NAME "epanet.__init__" -extern int __pyx_module_is_main_epanet____init__; -int __pyx_module_is_main_epanet____init__ = 0; - -/* Implementation of "epanet" */ -/* #### Code section: global_var ### */ -/* #### Code section: string_decls ### */ -static const char __pyx_k_[] = "."; -static const char __pyx_k__2[] = "?"; -static const char __pyx_k_main[] = "__main__"; -static const char __pyx_k_name[] = "__name__"; -static const char __pyx_k_test[] = "__test__"; -static const char __pyx_k_epanet[] = "epanet"; -static const char __pyx_k_module[] = "__module__"; -static const char __pyx_k_run_inp[] = "run_inp"; -static const char __pyx_k_qualname[] = "__qualname__"; -static const char __pyx_k_dump_output[] = "dump_output"; -static const char __pyx_k_run_project[] = "run_project"; -static const char __pyx_k_epanet___init[] = "epanet.__init__"; -static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; -static const char __pyx_k_run_project_return_dict[] = "run_project_return_dict"; -/* #### Code section: decls ### */ -/* #### Code section: late_includes ### */ -/* #### Code section: module_state ### */ -/* SmallCodeConfig */ -#ifndef CYTHON_SMALL_CODE -#if defined(__clang__) - #define CYTHON_SMALL_CODE -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - #define CYTHON_SMALL_CODE __attribute__((cold)) -#else - #define CYTHON_SMALL_CODE -#endif -#endif - -typedef struct { - PyObject *__pyx_d; - PyObject *__pyx_b; - PyObject *__pyx_cython_runtime; - PyObject *__pyx_empty_tuple; - PyObject *__pyx_empty_bytes; - PyObject *__pyx_empty_unicode; - #ifdef __Pyx_CyFunction_USED - PyTypeObject *__pyx_CyFunctionType; - #endif - #ifdef __Pyx_FusedFunction_USED - PyTypeObject *__pyx_FusedFunctionType; - #endif - #ifdef __Pyx_Generator_USED - PyTypeObject *__pyx_GeneratorType; - #endif - #ifdef __Pyx_IterableCoroutine_USED - PyTypeObject *__pyx_IterableCoroutineType; - #endif - #ifdef __Pyx_Coroutine_USED - PyTypeObject *__pyx_CoroutineAwaitType; - #endif - #ifdef __Pyx_Coroutine_USED - PyTypeObject *__pyx_CoroutineType; - #endif - PyObject *__pyx_string_tab[14]; -/* #### Code section: module_state_contents ### */ -/* CodeObjectCache.module_state_decls */ -struct __Pyx_CodeObjectCache __pyx_code_cache; - -/* #### Code section: module_state_end ### */ -} __pyx_mstatetype; - -#if CYTHON_USE_MODULE_STATE -#ifdef __cplusplus -namespace { -extern struct PyModuleDef __pyx_moduledef; -} /* anonymous namespace */ -#else -static struct PyModuleDef __pyx_moduledef; -#endif - -#define __pyx_mstate_global (__Pyx_PyModule_GetState(__Pyx_State_FindModule(&__pyx_moduledef))) - -#define __pyx_m (__Pyx_State_FindModule(&__pyx_moduledef)) -#else -static __pyx_mstatetype __pyx_mstate_global_static = -#ifdef __cplusplus - {}; -#else - {0}; -#endif -static __pyx_mstatetype * const __pyx_mstate_global = &__pyx_mstate_global_static; -#endif -/* #### Code section: constant_name_defines ### */ -#define __pyx_kp_u_ __pyx_string_tab[0] -#define __pyx_kp_u__2 __pyx_string_tab[1] -#define __pyx_n_u_cline_in_traceback __pyx_string_tab[2] -#define __pyx_n_u_dump_output __pyx_string_tab[3] -#define __pyx_n_u_epanet __pyx_string_tab[4] -#define __pyx_kp_u_epanet___init __pyx_string_tab[5] -#define __pyx_n_u_main __pyx_string_tab[6] -#define __pyx_n_u_module __pyx_string_tab[7] -#define __pyx_n_u_name __pyx_string_tab[8] -#define __pyx_n_u_qualname __pyx_string_tab[9] -#define __pyx_n_u_run_inp __pyx_string_tab[10] -#define __pyx_n_u_run_project __pyx_string_tab[11] -#define __pyx_n_u_run_project_return_dict __pyx_string_tab[12] -#define __pyx_n_u_test __pyx_string_tab[13] -/* #### Code section: module_state_clear ### */ -#if CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __pyx_m_clear(PyObject *m) { - __pyx_mstatetype *clear_module_state = __Pyx_PyModule_GetState(m); - if (!clear_module_state) return 0; - Py_CLEAR(clear_module_state->__pyx_d); - Py_CLEAR(clear_module_state->__pyx_b); - Py_CLEAR(clear_module_state->__pyx_cython_runtime); - Py_CLEAR(clear_module_state->__pyx_empty_tuple); - Py_CLEAR(clear_module_state->__pyx_empty_bytes); - Py_CLEAR(clear_module_state->__pyx_empty_unicode); - #ifdef __Pyx_CyFunction_USED - Py_CLEAR(clear_module_state->__pyx_CyFunctionType); - #endif - #ifdef __Pyx_FusedFunction_USED - Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); - #endif - #if CYTHON_PEP489_MULTI_PHASE_INIT - __Pyx_State_RemoveModule(NULL); - #endif - for (int i=0; i<14; ++i) { Py_CLEAR(clear_module_state->__pyx_string_tab[i]); } - return 0; -} -#endif -/* #### Code section: module_state_traverse ### */ -#if CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { - __pyx_mstatetype *traverse_module_state = __Pyx_PyModule_GetState(m); - if (!traverse_module_state) return 0; - Py_VISIT(traverse_module_state->__pyx_d); - Py_VISIT(traverse_module_state->__pyx_b); - Py_VISIT(traverse_module_state->__pyx_cython_runtime); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_tuple); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_bytes); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_unicode); - #ifdef __Pyx_CyFunction_USED - Py_VISIT(traverse_module_state->__pyx_CyFunctionType); - #endif - #ifdef __Pyx_FusedFunction_USED - Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); - #endif - for (int i=0; i<14; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_string_tab[i]); } - return 0; -} -#endif -/* #### Code section: module_code ### */ -/* #### Code section: module_exttypes ### */ - -static PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; -/* #### Code section: initfunc_declarations ### */ -static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate); /*proto*/ -/* #### Code section: init_module ### */ - -static int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); - /*--- Global init code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); - /*--- Variable export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); - /*--- Function export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); - /*--- Variable import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -#if CYTHON_PEP489_MULTI_PHASE_INIT -static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ -static int __pyx_pymod_exec_epanet(PyObject* module); /*proto*/ -static PyModuleDef_Slot __pyx_moduledef_slots[] = { - {Py_mod_create, (void*)__pyx_pymod_create}, - {Py_mod_exec, (void*)__pyx_pymod_exec_epanet}, - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - {Py_mod_gil, Py_MOD_GIL_USED}, - #endif - #if PY_VERSION_HEX >= 0x030C0000 && CYTHON_USE_MODULE_STATE - {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, - #endif - {0, NULL} -}; -#endif - -#ifdef __cplusplus -namespace { - struct PyModuleDef __pyx_moduledef = - #else - static struct PyModuleDef __pyx_moduledef = - #endif - { - PyModuleDef_HEAD_INIT, - "epanet", - 0, /* m_doc */ - #if CYTHON_USE_MODULE_STATE - sizeof(__pyx_mstatetype), /* m_size */ - #else - (CYTHON_PEP489_MULTI_PHASE_INIT) ? 0 : -1, /* m_size */ - #endif - __pyx_methods /* m_methods */, - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_moduledef_slots, /* m_slots */ - #else - NULL, /* m_reload */ - #endif - #if CYTHON_USE_MODULE_STATE - __pyx_m_traverse, /* m_traverse */ - __pyx_m_clear, /* m_clear */ - NULL /* m_free */ - #else - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ - #endif - }; - #ifdef __cplusplus -} /* anonymous namespace */ -#endif - -/* PyModInitFuncType */ -#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -#else - #ifdef __cplusplus - #define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else - #define __Pyx_PyMODINIT_FUNC PyObject * - #endif -#endif - -__Pyx_PyMODINIT_FUNC PyInit_epanet(void) CYTHON_SMALL_CODE; /*proto*/ -#if !defined(CYTHON_NO_PYINIT_EXPORT) && (defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS)) -__Pyx_PyMODINIT_FUNC PyInit___init__(void) { return PyInit_epanet(); } -#endif -__Pyx_PyMODINIT_FUNC PyInit_epanet(void) -#if CYTHON_PEP489_MULTI_PHASE_INIT -{ - return PyModuleDef_Init(&__pyx_moduledef); -} -/* ModuleCreationPEP489 */ -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x03090000 -static PY_INT64_T __Pyx_GetCurrentInterpreterId(void) { - { - PyObject *module = PyImport_ImportModule("_interpreters"); // 3.13+ I think - if (!module) { - PyErr_Clear(); // just try the 3.8-3.12 version - module = PyImport_ImportModule("_xxsubinterpreters"); - if (!module) goto bad; - } - PyObject *current = PyObject_CallMethod(module, "get_current", NULL); - Py_DECREF(module); - if (!current) goto bad; - if (PyTuple_Check(current)) { - PyObject *new_current = PySequence_GetItem(current, 0); - Py_DECREF(current); - current = new_current; - if (!new_current) goto bad; - } - long long as_c_int = PyLong_AsLongLong(current); - Py_DECREF(current); - return as_c_int; - } - bad: - PySys_WriteStderr("__Pyx_GetCurrentInterpreterId failed. Try setting the C define CYTHON_PEP489_MULTI_PHASE_INIT=0\n"); - return -1; -} -#endif -#if !CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { - static PY_INT64_T main_interpreter_id = -1; -#if CYTHON_COMPILING_IN_GRAAL - PY_INT64_T current_id = PyInterpreterState_GetIDFromThreadState(PyThreadState_Get()); -#elif CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX >= 0x03090000 - PY_INT64_T current_id = PyInterpreterState_GetID(PyInterpreterState_Get()); -#elif CYTHON_COMPILING_IN_LIMITED_API - PY_INT64_T current_id = __Pyx_GetCurrentInterpreterId(); -#else - PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); -#endif - if (unlikely(current_id == -1)) { - return -1; - } - if (main_interpreter_id == -1) { - main_interpreter_id = current_id; - return 0; - } else if (unlikely(main_interpreter_id != current_id)) { - PyErr_SetString( - PyExc_ImportError, - "Interpreter change detected - this module can only be loaded into one interpreter per process."); - return -1; - } - return 0; -} -#endif -static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) -{ - PyObject *value = PyObject_GetAttrString(spec, from_name); - int result = 0; - if (likely(value)) { - if (allow_none || value != Py_None) { - result = PyDict_SetItemString(moddict, to_name, value); - } - Py_DECREF(value); - } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - } else { - result = -1; - } - return result; -} -static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { - PyObject *module = NULL, *moddict, *modname; - CYTHON_UNUSED_VAR(def); - #if !CYTHON_USE_MODULE_STATE - if (__Pyx_check_single_interpreter()) - return NULL; - #endif - if (__pyx_m) - return __Pyx_NewRef(__pyx_m); - modname = PyObject_GetAttrString(spec, "name"); - if (unlikely(!modname)) goto bad; - module = PyModule_NewObject(modname); - Py_DECREF(modname); - if (unlikely(!module)) goto bad; - moddict = PyModule_GetDict(module); - if (unlikely(!moddict)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; - return module; -bad: - Py_XDECREF(module); - return NULL; -} - - -static CYTHON_SMALL_CODE int __pyx_pymod_exec_epanet(PyObject *__pyx_pyinit_module) -#endif -{ - int stringtab_initialized = 0; - #if CYTHON_USE_MODULE_STATE - int pystate_addmodule_run = 0; - #endif - __pyx_mstatetype *__pyx_mstate = NULL; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { - if (__pyx_m == __pyx_pyinit_module) return 0; - PyErr_SetString(PyExc_RuntimeError, "Module 'epanet' has already been imported. Re-initialisation is not supported."); - return -1; - } - #else - if (__pyx_m) return __Pyx_NewRef(__pyx_m); - #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_t_1 = __pyx_pyinit_module; - Py_INCREF(__pyx_t_1); - #else - __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #if CYTHON_USE_MODULE_STATE - { - int add_module_result = __Pyx_State_AddModule(__pyx_t_1, &__pyx_moduledef); - __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "epanet" pseudovariable */ - if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) - pystate_addmodule_run = 1; - } - #else - __pyx_m = __pyx_t_1; - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - PyUnstable_Module_SetGIL(__pyx_m, Py_MOD_GIL_USED); - #endif - __pyx_mstate = __pyx_mstate_global; - CYTHON_UNUSED_VAR(__pyx_t_1); - __pyx_mstate->__pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_mstate->__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) - Py_INCREF(__pyx_mstate->__pyx_d); - __pyx_mstate->__pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_mstate->__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_cython_runtime = __Pyx_PyImport_AddModuleRef("cython_runtime"); if (unlikely(!__pyx_mstate->__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_mstate->__pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /* ImportRefnannyAPI */ - #if CYTHON_REFNANNY -__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); -if (!__Pyx_RefNanny) { - PyErr_Clear(); - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); - if (!__Pyx_RefNanny) - Py_FatalError("failed to import 'refnanny' module"); -} -#endif - -__Pyx_RefNannySetupContext("PyInit_epanet", 0); - if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pxy_PyFrame_Initialize_Offsets - __Pxy_PyFrame_Initialize_Offsets(); - #endif - __pyx_mstate->__pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_mstate->__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pyx_CyFunction_USED - if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_FusedFunction_USED - if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Coroutine_USED - if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Generator_USED - if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_AsyncGen_USED - if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - /*--- Library function declarations ---*/ - /*--- Initialize various global constants etc. ---*/ - if (__Pyx_InitConstants(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - stringtab_initialized = 1; - if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__pyx_module_is_main_epanet____init__) { - if (PyObject_SetAttr(__pyx_m, __pyx_mstate_global->__pyx_n_u_name, __pyx_mstate_global->__pyx_n_u_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - } - if (!CYTHON_PEP489_MULTI_PHASE_INIT) { - if (unlikely((__Pyx_SetPackagePathFromImportLib(__pyx_mstate_global->__pyx_kp_u_epanet___init) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) - } - { - PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) - if (!PyDict_GetItemString(modules, "epanet")) { - if (unlikely((PyDict_SetItemString(modules, "epanet", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) - } - } - /*--- Builtin init code ---*/ - if (__Pyx_InitCachedBuiltins(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Constants init code ---*/ - if (__Pyx_InitCachedConstants(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__Pyx_CreateCodeObjects(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(__pyx_mstate); - (void)__Pyx_modinit_variable_export_code(__pyx_mstate); - (void)__Pyx_modinit_function_export_code(__pyx_mstate); - (void)__Pyx_modinit_type_init_code(__pyx_mstate); - (void)__Pyx_modinit_type_import_code(__pyx_mstate); - (void)__Pyx_modinit_variable_import_code(__pyx_mstate); - (void)__Pyx_modinit_function_import_code(__pyx_mstate); - /*--- Execution code ---*/ - - /* "epanet/__init__.py":1 - * from .epanet import run_project, run_project_return_dict, run_inp, dump_output # <<<<<<<<<<<<<< -*/ - __pyx_t_2 = __Pyx_PyList_Pack(4, __pyx_mstate_global->__pyx_n_u_run_project, __pyx_mstate_global->__pyx_n_u_run_project_return_dict, __pyx_mstate_global->__pyx_n_u_run_inp, __pyx_mstate_global->__pyx_n_u_dump_output); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_Import(__pyx_mstate_global->__pyx_n_u_epanet, __pyx_t_2, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_run_project); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_run_project, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_run_project_return_dict); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_run_project_return_dict, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_run_inp); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_run_inp, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_dump_output); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_dump_output, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_test, __pyx_t_3) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /*--- Wrapped vars code ---*/ - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - if (__pyx_m) { - if (__pyx_mstate->__pyx_d && stringtab_initialized) { - __Pyx_AddTraceback("init epanet", __pyx_clineno, __pyx_lineno, __pyx_filename); - } - #if !CYTHON_USE_MODULE_STATE - Py_CLEAR(__pyx_m); - #else - Py_DECREF(__pyx_m); - if (pystate_addmodule_run) { - PyObject *tp, *value, *tb; - PyErr_Fetch(&tp, &value, &tb); - PyState_RemoveModule(&__pyx_moduledef); - PyErr_Restore(tp, value, tb); - } - #endif - } else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ImportError, "init epanet"); - } - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - #if CYTHON_PEP489_MULTI_PHASE_INIT - return (__pyx_m != NULL) ? 0 : -1; - #else - return __pyx_m; - #endif -} -/* #### Code section: pystring_table ### */ - -typedef struct { - const char *s; -#if 23 <= 65535 - const unsigned short n; -#elif 23 / 2 < INT_MAX - const unsigned int n; -#elif 23 / 2 < LONG_MAX - const unsigned long n; -#else - const Py_ssize_t n; -#endif -#if 1 <= 31 - const unsigned int encoding : 5; -#elif 1 <= 255 - const unsigned char encoding; -#elif 1 <= 65535 - const unsigned short encoding; -#else - const Py_ssize_t encoding; -#endif - const unsigned int is_unicode : 1; - const unsigned int intern : 1; -} __Pyx_StringTabEntry; -static const char * const __pyx_string_tab_encodings[] = { 0 }; -static const __Pyx_StringTabEntry __pyx_string_tab[] = { - {__pyx_k_, sizeof(__pyx_k_), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_ */ - {__pyx_k__2, sizeof(__pyx_k__2), 0, 1, 0}, /* PyObject cname: __pyx_kp_u__2 */ - {__pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 1, 1}, /* PyObject cname: __pyx_n_u_cline_in_traceback */ - {__pyx_k_dump_output, sizeof(__pyx_k_dump_output), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dump_output */ - {__pyx_k_epanet, sizeof(__pyx_k_epanet), 0, 1, 1}, /* PyObject cname: __pyx_n_u_epanet */ - {__pyx_k_epanet___init, sizeof(__pyx_k_epanet___init), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_epanet___init */ - {__pyx_k_main, sizeof(__pyx_k_main), 0, 1, 1}, /* PyObject cname: __pyx_n_u_main */ - {__pyx_k_module, sizeof(__pyx_k_module), 0, 1, 1}, /* PyObject cname: __pyx_n_u_module */ - {__pyx_k_name, sizeof(__pyx_k_name), 0, 1, 1}, /* PyObject cname: __pyx_n_u_name */ - {__pyx_k_qualname, sizeof(__pyx_k_qualname), 0, 1, 1}, /* PyObject cname: __pyx_n_u_qualname */ - {__pyx_k_run_inp, sizeof(__pyx_k_run_inp), 0, 1, 1}, /* PyObject cname: __pyx_n_u_run_inp */ - {__pyx_k_run_project, sizeof(__pyx_k_run_project), 0, 1, 1}, /* PyObject cname: __pyx_n_u_run_project */ - {__pyx_k_run_project_return_dict, sizeof(__pyx_k_run_project_return_dict), 0, 1, 1}, /* PyObject cname: __pyx_n_u_run_project_return_dict */ - {__pyx_k_test, sizeof(__pyx_k_test), 0, 1, 1}, /* PyObject cname: __pyx_n_u_test */ - {0, 0, 0, 0, 0} -}; -/* InitStrings.proto */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry const *t, PyObject **target, const char* const* encoding_names); - -/* #### Code section: cached_builtins ### */ - -static int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - return 0; -} -/* #### Code section: cached_constants ### */ - -static int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); - __Pyx_RefNannyFinishContext(); - return 0; -} -/* #### Code section: init_constants ### */ - -static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - if (__Pyx_InitStrings(__pyx_string_tab, __pyx_mstate->__pyx_string_tab, __pyx_string_tab_encodings) < 0) __PYX_ERR(0, 1, __pyx_L1_error); - return 0; - __pyx_L1_error:; - return -1; -} -/* #### Code section: init_codeobjects ### */ - -static int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - return 0; -} -/* #### Code section: init_globals ### */ - -static int __Pyx_InitGlobals(void) { - /* PythonCompatibility.init */ - if (likely(__Pyx_init_co_variables() == 0)); else - -if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) - - return 0; - __pyx_L1_error:; - return -1; -} -/* #### Code section: cleanup_globals ### */ -/* #### Code section: cleanup_module ### */ -/* #### Code section: main_method ### */ -/* #### Code section: utility_code_pragmas ### */ -#ifdef _MSC_VER -#pragma warning( push ) -/* Warning 4127: conditional expression is constant - * Cython uses constant conditional expressions to allow in inline functions to be optimized at - * compile-time, so this warning is not useful - */ -#pragma warning( disable : 4127 ) -#endif - - - -/* #### Code section: utility_code_def ### */ - -/* --- Runtime support code --- */ -/* Refnanny */ -#if CYTHON_REFNANNY -static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule(modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, "RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); -end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; -} -#endif - -/* SetPackagePathFromImportLib */ -#if !CYTHON_PEP489_MULTI_PHASE_INIT -static int __Pyx_SetPackagePathFromImportLib(PyObject *module_name) { - PyObject *importlib, *osmod, *ossep, *parts, *package_path; - PyObject *file_path = NULL; - PyObject *item; - int result; - PyObject *spec; - importlib = PyImport_ImportModule("importlib.util"); - if (unlikely(!importlib)) - goto bad; - spec = PyObject_CallMethod(importlib, "find_spec", "(O)", module_name); - Py_DECREF(importlib); - if (unlikely(!spec)) - goto bad; - file_path = PyObject_GetAttrString(spec, "origin"); - Py_DECREF(spec); - if (unlikely(!file_path)) - goto bad; - if (unlikely(PyObject_SetAttrString(__pyx_m, "__file__", file_path) < 0)) - goto bad; - osmod = PyImport_ImportModule("os"); - if (unlikely(!osmod)) - goto bad; - ossep = PyObject_GetAttrString(osmod, "sep"); - Py_DECREF(osmod); - if (unlikely(!ossep)) - goto bad; - parts = PyObject_CallMethod(file_path, "rsplit", "(Oi)", ossep, 1); - Py_DECREF(file_path); file_path = NULL; - Py_DECREF(ossep); - if (unlikely(!parts)) - goto bad; -#if CYTHON_ASSUME_SAFE_MACROS - package_path = Py_BuildValue("[O]", PyList_GET_ITEM(parts, 0)); -#else - item = PyList_GetItem(parts, 0); - if (unlikely(!item)) - goto bad; - package_path = Py_BuildValue("[O]", item); -#endif - Py_DECREF(parts); - if (unlikely(!package_path)) - goto bad; - goto set_path; -bad: - PyErr_WriteUnraisable(module_name); - Py_XDECREF(file_path); - PyErr_Clear(); - package_path = PyList_New(0); - if (unlikely(!package_path)) - return -1; -set_path: - result = PyObject_SetAttrString(__pyx_m, "__path__", package_path); - Py_DECREF(package_path); - return result; -} -#endif - -/* ListPack */ -static PyObject *__Pyx_PyList_Pack(Py_ssize_t n, ...) { - va_list va; - PyObject *l = PyList_New(n); - va_start(va, n); - if (unlikely(!l)) goto end; - for (Py_ssize_t i=0; itp_getattro)) - return tp->tp_getattro(obj, attr_name); - return PyObject_GetAttr(obj, attr_name); -} -#endif - -/* Import */ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - PyObject *module = 0; - PyObject *empty_dict = 0; - PyObject *empty_list = 0; - empty_dict = PyDict_New(); - if (unlikely(!empty_dict)) - goto bad; - if (level == -1) { - if (strchr(__Pyx_MODULE_NAME, '.') != (0)) { - module = PyImport_ImportModuleLevelObject( - name, __pyx_mstate_global->__pyx_d, empty_dict, from_list, 1); - if (unlikely(!module)) { - if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) - goto bad; - PyErr_Clear(); - } - } - level = 0; - } - if (!module) { - module = PyImport_ImportModuleLevelObject( - name, __pyx_mstate_global->__pyx_d, empty_dict, from_list, level); - } -bad: - Py_XDECREF(empty_dict); - Py_XDECREF(empty_list); - return module; -} - -/* ImportFrom */ -static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name) { - PyObject* value = __Pyx_PyObject_GetAttrStr(module, name); - if (unlikely(!value) && PyErr_ExceptionMatches(PyExc_AttributeError)) { - const char* module_name_str = 0; - PyObject* module_name = 0; - PyObject* module_dot = 0; - PyObject* full_name = 0; - PyErr_Clear(); - module_name_str = PyModule_GetName(module); - if (unlikely(!module_name_str)) { goto modbad; } - module_name = PyUnicode_FromString(module_name_str); - if (unlikely(!module_name)) { goto modbad; } - module_dot = PyUnicode_Concat(module_name, __pyx_mstate_global->__pyx_kp_u_); - if (unlikely(!module_dot)) { goto modbad; } - full_name = PyUnicode_Concat(module_dot, name); - if (unlikely(!full_name)) { goto modbad; } - #if (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) ||\ - CYTHON_COMPILING_IN_GRAAL - { - PyObject *modules = PyImport_GetModuleDict(); - if (unlikely(!modules)) - goto modbad; - value = PyObject_GetItem(modules, full_name); - } - #else - value = PyImport_GetModule(full_name); - #endif - modbad: - Py_XDECREF(full_name); - Py_XDECREF(module_dot); - Py_XDECREF(module_name); - } - if (unlikely(!value)) { - PyErr_Format(PyExc_ImportError, "cannot import name %S", name); - } - return value; -} - -/* PyDictVersioning */ -#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { - PyObject *dict = Py_TYPE(obj)->tp_dict; - return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { - PyObject **dictptr = NULL; - Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; - if (offset) { -#if CYTHON_COMPILING_IN_CPYTHON - dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); -#else - dictptr = _PyObject_GetDictPtr(obj); -#endif - } - return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; -} -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { - PyObject *dict = Py_TYPE(obj)->tp_dict; - if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) - return 0; - return obj_dict_version == __Pyx_get_object_dict_version(obj); -} -#endif - -/* PyErrExceptionMatches */ -#if CYTHON_FAST_THREAD_STATE -static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(tuple); - for (i=0; i= 0x030C00A6 - PyObject *current_exception = tstate->current_exception; - if (unlikely(!current_exception)) return 0; - exc_type = (PyObject*) Py_TYPE(current_exception); - if (exc_type == err) return 1; -#else - exc_type = tstate->curexc_type; - if (exc_type == err) return 1; - if (unlikely(!exc_type)) return 0; -#endif - #if CYTHON_AVOID_BORROWED_REFS - Py_INCREF(exc_type); - #endif - if (unlikely(PyTuple_Check(err))) { - result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); - } else { - result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); - } - #if CYTHON_AVOID_BORROWED_REFS - Py_DECREF(exc_type); - #endif - return result; -} -#endif - -/* PyErrFetchRestore */ -#if CYTHON_FAST_THREAD_STATE -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { -#if PY_VERSION_HEX >= 0x030C00A6 - PyObject *tmp_value; - assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); - if (value) { - #if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) - #endif - PyException_SetTraceback(value, tb); - } - tmp_value = tstate->current_exception; - tstate->current_exception = value; - Py_XDECREF(tmp_value); - Py_XDECREF(type); - Py_XDECREF(tb); -#else - PyObject *tmp_type, *tmp_value, *tmp_tb; - tmp_type = tstate->curexc_type; - tmp_value = tstate->curexc_value; - tmp_tb = tstate->curexc_traceback; - tstate->curexc_type = type; - tstate->curexc_value = value; - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -#endif -} -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { -#if PY_VERSION_HEX >= 0x030C00A6 - PyObject* exc_value; - exc_value = tstate->current_exception; - tstate->current_exception = 0; - *value = exc_value; - *type = NULL; - *tb = NULL; - if (exc_value) { - *type = (PyObject*) Py_TYPE(exc_value); - Py_INCREF(*type); - #if CYTHON_COMPILING_IN_CPYTHON - *tb = ((PyBaseExceptionObject*) exc_value)->traceback; - Py_XINCREF(*tb); - #else - *tb = PyException_GetTraceback(exc_value); - #endif - } -#else - *type = tstate->curexc_type; - *value = tstate->curexc_value; - *tb = tstate->curexc_traceback; - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; -#endif -} -#endif - -/* PyObjectGetAttrStrNoError */ -#if __PYX_LIMITED_VERSION_HEX < 0x030d0000 -static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) - __Pyx_PyErr_Clear(); -} -#endif -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { - PyObject *result; -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - (void) PyObject_GetOptionalAttr(obj, attr_name, &result); - return result; -#else -#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { - return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); - } -#endif - result = __Pyx_PyObject_GetAttrStr(obj, attr_name); - if (unlikely(!result)) { - __Pyx_PyObject_GetAttrStr_ClearAttributeError(); - } - return result; -#endif -} - -/* CLineInTraceback */ -#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME -static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; -#if CYTHON_COMPILING_IN_CPYTHON - PyObject **cython_runtime_dict; -#endif - CYTHON_MAYBE_UNUSED_VAR(tstate); - if (unlikely(!__pyx_mstate_global->__pyx_cython_runtime)) { - return c_line; - } - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); -#if CYTHON_COMPILING_IN_CPYTHON - cython_runtime_dict = _PyObject_GetDictPtr(__pyx_mstate_global->__pyx_cython_runtime); - if (likely(cython_runtime_dict)) { - __Pyx_BEGIN_CRITICAL_SECTION(*cython_runtime_dict); - __PYX_PY_DICT_LOOKUP_IF_MODIFIED( - use_cline, *cython_runtime_dict, - __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_mstate_global->__pyx_n_u_cline_in_traceback)) - Py_XINCREF(use_cline); - __Pyx_END_CRITICAL_SECTION(); - } else -#endif - { - PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_mstate_global->__pyx_cython_runtime, __pyx_mstate_global->__pyx_n_u_cline_in_traceback); - if (use_cline_obj) { - use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; - Py_INCREF(use_cline); - Py_DECREF(use_cline_obj); - } else { - PyErr_Clear(); - use_cline = NULL; - } - } - if (!use_cline) { - c_line = 0; - (void) PyObject_SetAttr(__pyx_mstate_global->__pyx_cython_runtime, __pyx_mstate_global->__pyx_n_u_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; - } - Py_XDECREF(use_cline); - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - return c_line; -} -#endif - -/* CodeObjectCache */ -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { - int start = 0, mid = 0, end = count - 1; - if (end >= 0 && code_line > entries[end].code_line) { - return count; - } - while (start < end) { - mid = start + (end - start) / 2; - if (code_line < entries[mid].code_line) { - end = mid; - } else if (code_line > entries[mid].code_line) { - start = mid + 1; - } else { - return mid; - } - } - if (code_line <= entries[mid].code_line) { - return mid; - } else { - return mid + 1; - } -} -static __Pyx_CachedCodeObjectType *__pyx__find_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line) { - __Pyx_CachedCodeObjectType* code_object; - int pos; - if (unlikely(!code_line) || unlikely(!code_cache->entries)) { - return NULL; - } - pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); - if (unlikely(pos >= code_cache->count) || unlikely(code_cache->entries[pos].code_line != code_line)) { - return NULL; - } - code_object = code_cache->entries[pos].code_object; - Py_INCREF(code_object); - return code_object; -} -static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line) { -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS - (void)__pyx__find_code_object; - return NULL; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just miss. -#else - struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_nonatomic_int_type old_count = __pyx_atomic_incr_acq_rel(&code_cache->accessor_count); - if (old_count < 0) { - __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); - return NULL; - } -#endif - __Pyx_CachedCodeObjectType *result = __pyx__find_code_object(code_cache, code_line); -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); -#endif - return result; -#endif -} -static void __pyx__insert_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line, __Pyx_CachedCodeObjectType* code_object) -{ - int pos, i; - __Pyx_CodeObjectCacheEntry* entries = code_cache->entries; - if (unlikely(!code_line)) { - return; - } - if (unlikely(!entries)) { - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); - if (likely(entries)) { - code_cache->entries = entries; - code_cache->max_count = 64; - code_cache->count = 1; - entries[0].code_line = code_line; - entries[0].code_object = code_object; - Py_INCREF(code_object); - } - return; - } - pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); - if ((pos < code_cache->count) && unlikely(code_cache->entries[pos].code_line == code_line)) { - __Pyx_CachedCodeObjectType* tmp = entries[pos].code_object; - entries[pos].code_object = code_object; - Py_INCREF(code_object); - Py_DECREF(tmp); - return; - } - if (code_cache->count == code_cache->max_count) { - int new_max = code_cache->max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( - code_cache->entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } - code_cache->entries = entries; - code_cache->max_count = new_max; - } - for (i=code_cache->count; i>pos; i--) { - entries[i] = entries[i-1]; - } - entries[pos].code_line = code_line; - entries[pos].code_object = code_object; - code_cache->count++; - Py_INCREF(code_object); -} -static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object) { -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS - (void)__pyx__insert_code_object; - return; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just fail. -#else - struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_nonatomic_int_type expected = 0; - if (!__pyx_atomic_int_cmp_exchange(&code_cache->accessor_count, &expected, INT_MIN)) { - return; - } -#endif - __pyx__insert_code_object(code_cache, code_line, code_object); -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_sub(&code_cache->accessor_count, INT_MIN); -#endif -#endif -} - -/* AddTraceback */ -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" -#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API && !defined(PYPY_VERSION) - #ifndef Py_BUILD_CORE - #define Py_BUILD_CORE 1 - #endif - #include "internal/pycore_frame.h" -#endif -#if CYTHON_COMPILING_IN_LIMITED_API -static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, - PyObject *firstlineno, PyObject *name) { - PyObject *replace = NULL; - if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; - if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; - replace = PyObject_GetAttrString(code, "replace"); - if (likely(replace)) { - PyObject *result = PyObject_Call(replace, __pyx_mstate_global->__pyx_empty_tuple, scratch_dict); - Py_DECREF(replace); - return result; - } - PyErr_Clear(); - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; - PyObject *replace = NULL, *getframe = NULL, *frame = NULL; - PyObject *exc_type, *exc_value, *exc_traceback; - int success = 0; - if (c_line) { - (void) __pyx_cfilenm; - (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); - } - PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); - code_object = __pyx_find_code_object(c_line ? -c_line : py_line); - if (!code_object) { - code_object = Py_CompileString("_getframe()", filename, Py_eval_input); - if (unlikely(!code_object)) goto bad; - py_py_line = PyLong_FromLong(py_line); - if (unlikely(!py_py_line)) goto bad; - py_funcname = PyUnicode_FromString(funcname); - if (unlikely(!py_funcname)) goto bad; - dict = PyDict_New(); - if (unlikely(!dict)) goto bad; - { - PyObject *old_code_object = code_object; - code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); - Py_DECREF(old_code_object); - } - if (unlikely(!code_object)) goto bad; - __pyx_insert_code_object(c_line ? -c_line : py_line, code_object); - } else { - dict = PyDict_New(); - } - getframe = PySys_GetObject("_getframe"); - if (unlikely(!getframe)) goto bad; - if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; - frame = PyEval_EvalCode(code_object, dict, dict); - if (unlikely(!frame) || frame == Py_None) goto bad; - success = 1; - bad: - PyErr_Restore(exc_type, exc_value, exc_traceback); - Py_XDECREF(code_object); - Py_XDECREF(py_py_line); - Py_XDECREF(py_funcname); - Py_XDECREF(dict); - Py_XDECREF(replace); - if (success) { - PyTraceBack_Here( - (struct _frame*)frame); - } - Py_XDECREF(frame); -} -#else -static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = NULL; - PyObject *py_funcname = NULL; - if (c_line) { - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); - if (!py_funcname) goto bad; - funcname = PyUnicode_AsUTF8(py_funcname); - if (!funcname) goto bad; - } - py_code = PyCode_NewEmpty(filename, funcname, py_line); - Py_XDECREF(py_funcname); - return py_code; -bad: - Py_XDECREF(py_funcname); - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject *ptype, *pvalue, *ptraceback; - if (c_line) { - c_line = __Pyx_CLineForTraceback(tstate, c_line); - } - py_code = __pyx_find_code_object(c_line ? -c_line : py_line); - if (!py_code) { - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); - py_code = __Pyx_CreateCodeObjectForTraceback( - funcname, c_line, py_line, filename); - if (!py_code) { - /* If the code object creation fails, then we should clear the - fetched exception references and propagate the new exception */ - Py_XDECREF(ptype); - Py_XDECREF(pvalue); - Py_XDECREF(ptraceback); - goto bad; - } - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); - } - py_frame = PyFrame_New( - tstate, /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - __pyx_mstate_global->__pyx_d, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - __Pyx_PyFrame_SetLineNumber(py_frame, py_line); - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} -#endif - -/* FormatTypeName */ -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030d0000 -static __Pyx_TypeName -__Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp) -{ - PyObject *module = NULL, *name = NULL, *result = NULL; - #if __PYX_LIMITED_VERSION_HEX < 0x030b0000 - name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, - __pyx_mstate_global->__pyx_n_u_qualname); - #else - name = PyType_GetQualName(tp); - #endif - if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) goto bad; - module = __Pyx_PyObject_GetAttrStr((PyObject *)tp, - __pyx_mstate_global->__pyx_n_u_module); - if (unlikely(module == NULL) || unlikely(!PyUnicode_Check(module))) goto bad; - if (PyUnicode_CompareWithASCIIString(module, "builtins") == 0) { - result = name; - name = NULL; - goto done; - } - result = PyUnicode_FromFormat("%U.%U", module, name); - if (unlikely(result == NULL)) goto bad; - done: - Py_XDECREF(name); - Py_XDECREF(module); - return result; - bad: - PyErr_Clear(); - if (name) { - result = name; - name = NULL; - } else { - result = __Pyx_NewRef(__pyx_mstate_global->__pyx_kp_u__2); - } - goto done; -} -#endif - -/* PyFunctionFastCall */ -#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL -static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject *const *args, Py_ssize_t na, - PyObject *globals) { - PyFrameObject *f; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject **fastlocals; - Py_ssize_t i; - PyObject *result; - assert(globals != NULL); - /* XXX Perhaps we should create a specialized - PyFrame_New() that doesn't take locals, but does - take builtins without sanity checking them. - */ - assert(tstate != NULL); - f = PyFrame_New(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - fastlocals = __Pyx_PyFrame_GetLocalsplus(f); - for (i = 0; i < na; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - result = PyEval_EvalFrameEx(f,0); - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - return result; -} -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs) { - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *closure; - PyObject *kwdefs; - PyObject *kwtuple, **k; - PyObject **d; - Py_ssize_t nd; - Py_ssize_t nk; - PyObject *result; - assert(kwargs == NULL || PyDict_Check(kwargs)); - nk = kwargs ? PyDict_Size(kwargs) : 0; - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { - return NULL; - } - if ( - co->co_kwonlyargcount == 0 && - likely(kwargs == NULL || nk == 0) && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { - if (argdefs == NULL && co->co_argcount == nargs) { - result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); - goto done; - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - args = &PyTuple_GET_ITEM(argdefs, 0); - result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); - goto done; - } - } - if (kwargs != NULL) { - Py_ssize_t pos, i; - kwtuple = PyTuple_New(2 * nk); - if (kwtuple == NULL) { - result = NULL; - goto done; - } - k = &PyTuple_GET_ITEM(kwtuple, 0); - pos = i = 0; - while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { - Py_INCREF(k[i]); - Py_INCREF(k[i+1]); - i += 2; - } - nk = i / 2; - } - else { - kwtuple = NULL; - k = NULL; - } - closure = PyFunction_GET_CLOSURE(func); - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, - args, (int)nargs, - k, (int)nk, - d, (int)nd, kwdefs, closure); - Py_XDECREF(kwtuple); -done: - Py_LeaveRecursiveCall(); - return result; -} -#endif - -/* PyObjectCall */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; - ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) - return NULL; - result = (*call)(func, arg, kw); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* PyObjectCallMethO */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { - PyObject *self, *result; - PyCFunction cfunc; - cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); - self = __Pyx_CyOrPyCFunction_GET_SELF(func); - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) - return NULL; - result = cfunc(self, arg); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* PyObjectFastCall */ -#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API -static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs) { - PyObject *argstuple; - PyObject *result = 0; - size_t i; - argstuple = PyTuple_New((Py_ssize_t)nargs); - if (unlikely(!argstuple)) return NULL; - for (i = 0; i < nargs; i++) { - Py_INCREF(args[i]); - if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) != (0)) goto bad; - } - result = __Pyx_PyObject_Call(func, argstuple, kwargs); - bad: - Py_DECREF(argstuple); - return result; -} -#endif -#if CYTHON_VECTORCALL && !CYTHON_COMPILING_IN_LIMITED_API - #if PY_VERSION_HEX < 0x03090000 - #define __Pyx_PyVectorcall_Function(callable) _PyVectorcall_Function(callable) - #elif CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE vectorcallfunc __Pyx_PyVectorcall_Function(PyObject *callable) { - PyTypeObject *tp = Py_TYPE(callable); - #if defined(__Pyx_CyFunction_USED) - if (__Pyx_CyFunction_CheckExact(callable)) { - return __Pyx_CyFunction_func_vectorcall(callable); - } - #endif - if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL)) { - return NULL; - } - assert(PyCallable_Check(callable)); - Py_ssize_t offset = tp->tp_vectorcall_offset; - assert(offset > 0); - vectorcallfunc ptr; - memcpy(&ptr, (char *) callable + offset, sizeof(ptr)); - return ptr; -} - #else - #define __Pyx_PyVectorcall_Function(callable) PyVectorcall_Function(callable) - #endif -#endif -static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject *const *args, size_t _nargs, PyObject *kwargs) { - Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); -#if CYTHON_COMPILING_IN_CPYTHON - if (nargs == 0 && kwargs == NULL) { - if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) - return __Pyx_PyObject_CallMethO(func, NULL); - } - else if (nargs == 1 && kwargs == NULL) { - if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) - return __Pyx_PyObject_CallMethO(func, args[0]); - } -#endif - #if PY_VERSION_HEX < 0x030800B1 - #if CYTHON_FAST_PYCCALL - if (PyCFunction_Check(func)) { - if (kwargs) { - return _PyCFunction_FastCallDict(func, args, nargs, kwargs); - } else { - return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); - } - } - if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { - return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); - } - #endif - #if CYTHON_FAST_PYCALL - if (PyFunction_Check(func)) { - return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); - } - #endif - #endif - if (kwargs == NULL) { - #if CYTHON_VECTORCALL && !CYTHON_COMPILING_IN_LIMITED_API - vectorcallfunc f = __Pyx_PyVectorcall_Function(func); - if (f) { - return f(func, args, _nargs, NULL); - } - #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL - if (__Pyx_CyFunction_CheckExact(func)) { - __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); - if (f) return f(func, args, _nargs, NULL); - } - #elif CYTHON_COMPILING_IN_LIMITED_API && CYTHON_VECTORCALL - return PyObject_Vectorcall(func, args, _nargs, NULL); - #endif - } - if (nargs == 0) { - return __Pyx_PyObject_Call(func, __pyx_mstate_global->__pyx_empty_tuple, kwargs); - } - #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API - return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); - #else - return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); - #endif -} - -/* PyObjectVectorCallKwBuilder */ -#if CYTHON_VECTORCALL -static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - (void)__Pyx_PyObject_FastCallDict; - if (__Pyx_PyTuple_SET_ITEM(builder, n, key) != (0)) return -1; - Py_INCREF(key); - args[n] = value; - return 0; -} -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - (void)__Pyx_VectorcallBuilder_AddArgStr; - if (unlikely(!PyUnicode_Check(key))) { - PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return -1; - } - return __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n); -} -static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - PyObject *pyKey = PyUnicode_FromString(key); - if (!pyKey) return -1; - return __Pyx_VectorcallBuilder_AddArg(pyKey, value, builder, args, n); -} -#else // CYTHON_VECTORCALL -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, CYTHON_UNUSED PyObject **args, CYTHON_UNUSED int n) { - if (unlikely(!PyUnicode_Check(key))) { - PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return -1; - } - return PyDict_SetItem(builder, key, value); -} -#endif - -/* CIntToPy */ -static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { - return PyLong_FromLong((long) value); - } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -#endif - } - } else { - if (sizeof(long) <= sizeof(long)) { - return PyLong_FromLong((long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); -#endif - } - } - { - unsigned char *bytes = (unsigned char *)&value; -#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 - if (is_unsigned) { - return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); - } else { - return PyLong_FromNativeBytes(bytes, sizeof(value), -1); - } -#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 - int one = 1; int little = (int)*(unsigned char *)&one; - return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); -#else - int one = 1; int little = (int)*(unsigned char *)&one; - PyObject *from_bytes, *result = NULL, *kwds = NULL; - PyObject *py_bytes = NULL, *order_str = NULL; - from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); - if (!from_bytes) return NULL; - py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); - if (!py_bytes) goto limited_bad; - order_str = PyUnicode_FromString(little ? "little" : "big"); - if (!order_str) goto limited_bad; - { - PyObject *args[3+(CYTHON_VECTORCALL ? 1 : 0)] = { NULL, py_bytes, order_str }; - if (!is_unsigned) { - kwds = __Pyx_MakeVectorcallBuilderKwds(1); - if (!kwds) goto limited_bad; - if (__Pyx_VectorcallBuilder_AddArgStr("signed", __Pyx_NewRef(Py_True), kwds, args+3, 0) < 0) goto limited_bad; - } - result = __Pyx_Object_Vectorcall_CallFromBuilder(from_bytes, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET, kwds); - } - limited_bad: - Py_XDECREF(kwds); - Py_XDECREF(order_str); - Py_XDECREF(py_bytes); - Py_XDECREF(from_bytes); - return result; -#endif - } -} - -/* CIntFromPyVerify */ -#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ - {\ - func_type value = func_value;\ - if (sizeof(target_type) < sizeof(func_type)) {\ - if (unlikely(value != (func_type) (target_type) value)) {\ - func_type zero = 0;\ - if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ - return (target_type) -1;\ - if (is_unsigned && unlikely(value < zero))\ - goto raise_neg_overflow;\ - else\ - goto raise_overflow;\ - }\ - }\ - return (target_type) value;\ - } - -/* CIntFromPy */ -static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (unlikely(!PyLong_Check(x))) { - long val; - PyObject *tmp = __Pyx_PyNumber_Long(x); - if (!tmp) return (long) -1; - val = __Pyx_PyLong_As_long(tmp); - Py_DECREF(tmp); - return val; - } - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - if (unlikely(__Pyx_PyLong_IsNeg(x))) { - goto raise_neg_overflow; - } else if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_DigitCount(x)) { - case 2: - if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { - return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: - if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { - return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: - if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { - return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - } - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if ((sizeof(long) <= sizeof(unsigned long))) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_SignedDigitCount(x)) { - case -2: - if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: - if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: - if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: - if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: - if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: - if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { - return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - } -#endif - if ((sizeof(long) <= sizeof(long))) { - __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { - long val; - int ret = -1; -#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API - Py_ssize_t bytes_copied = PyLong_AsNativeBytes( - x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); - if (unlikely(bytes_copied == -1)) { - } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { - goto raise_overflow; - } else { - ret = 0; - } -#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - ret = _PyLong_AsByteArray((PyLongObject *)x, - bytes, sizeof(val), - is_little, !is_unsigned); -#else - PyObject *v; - PyObject *stepval = NULL, *mask = NULL, *shift = NULL; - int bits, remaining_bits, is_negative = 0; - int chunk_size = (sizeof(long) < 8) ? 30 : 62; - if (likely(PyLong_CheckExact(x))) { - v = __Pyx_NewRef(x); - } else { - v = PyNumber_Long(x); - if (unlikely(!v)) return (long) -1; - assert(PyLong_CheckExact(v)); - } - { - int result = PyObject_RichCompareBool(v, Py_False, Py_LT); - if (unlikely(result < 0)) { - Py_DECREF(v); - return (long) -1; - } - is_negative = result == 1; - } - if (is_unsigned && unlikely(is_negative)) { - Py_DECREF(v); - goto raise_neg_overflow; - } else if (is_negative) { - stepval = PyNumber_Invert(v); - Py_DECREF(v); - if (unlikely(!stepval)) - return (long) -1; - } else { - stepval = v; - } - v = NULL; - val = (long) 0; - mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; - shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; - for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { - PyObject *tmp, *digit; - long idigit; - digit = PyNumber_And(stepval, mask); - if (unlikely(!digit)) goto done; - idigit = PyLong_AsLong(digit); - Py_DECREF(digit); - if (unlikely(idigit < 0)) goto done; - val |= ((long) idigit) << bits; - tmp = PyNumber_Rshift(stepval, shift); - if (unlikely(!tmp)) goto done; - Py_DECREF(stepval); stepval = tmp; - } - Py_DECREF(shift); shift = NULL; - Py_DECREF(mask); mask = NULL; - { - long idigit = PyLong_AsLong(stepval); - if (unlikely(idigit < 0)) goto done; - remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); - if (unlikely(idigit >= (1L << remaining_bits))) - goto raise_overflow; - val |= ((long) idigit) << bits; - } - if (!is_unsigned) { - if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) - goto raise_overflow; - if (is_negative) - val = ~val; - } - ret = 0; - done: - Py_XDECREF(shift); - Py_XDECREF(mask); - Py_XDECREF(stepval); -#endif - if (unlikely(ret)) - return (long) -1; - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to long"); - return (long) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long) -1; -} - -/* CIntFromPy */ -static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const int neg_one = (int) -1, const_zero = (int) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (unlikely(!PyLong_Check(x))) { - int val; - PyObject *tmp = __Pyx_PyNumber_Long(x); - if (!tmp) return (int) -1; - val = __Pyx_PyLong_As_int(tmp); - Py_DECREF(tmp); - return val; - } - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - if (unlikely(__Pyx_PyLong_IsNeg(x))) { - goto raise_neg_overflow; - } else if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_DigitCount(x)) { - case 2: - if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { - return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: - if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { - return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: - if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { - return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - } - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if ((sizeof(int) <= sizeof(unsigned long))) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_SignedDigitCount(x)) { - case -2: - if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: - if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: - if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: - if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: - if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: - if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { - return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - } -#endif - if ((sizeof(int) <= sizeof(long))) { - __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { - int val; - int ret = -1; -#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API - Py_ssize_t bytes_copied = PyLong_AsNativeBytes( - x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); - if (unlikely(bytes_copied == -1)) { - } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { - goto raise_overflow; - } else { - ret = 0; - } -#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - ret = _PyLong_AsByteArray((PyLongObject *)x, - bytes, sizeof(val), - is_little, !is_unsigned); -#else - PyObject *v; - PyObject *stepval = NULL, *mask = NULL, *shift = NULL; - int bits, remaining_bits, is_negative = 0; - int chunk_size = (sizeof(long) < 8) ? 30 : 62; - if (likely(PyLong_CheckExact(x))) { - v = __Pyx_NewRef(x); - } else { - v = PyNumber_Long(x); - if (unlikely(!v)) return (int) -1; - assert(PyLong_CheckExact(v)); - } - { - int result = PyObject_RichCompareBool(v, Py_False, Py_LT); - if (unlikely(result < 0)) { - Py_DECREF(v); - return (int) -1; - } - is_negative = result == 1; - } - if (is_unsigned && unlikely(is_negative)) { - Py_DECREF(v); - goto raise_neg_overflow; - } else if (is_negative) { - stepval = PyNumber_Invert(v); - Py_DECREF(v); - if (unlikely(!stepval)) - return (int) -1; - } else { - stepval = v; - } - v = NULL; - val = (int) 0; - mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; - shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; - for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { - PyObject *tmp, *digit; - long idigit; - digit = PyNumber_And(stepval, mask); - if (unlikely(!digit)) goto done; - idigit = PyLong_AsLong(digit); - Py_DECREF(digit); - if (unlikely(idigit < 0)) goto done; - val |= ((int) idigit) << bits; - tmp = PyNumber_Rshift(stepval, shift); - if (unlikely(!tmp)) goto done; - Py_DECREF(stepval); stepval = tmp; - } - Py_DECREF(shift); shift = NULL; - Py_DECREF(mask); mask = NULL; - { - long idigit = PyLong_AsLong(stepval); - if (unlikely(idigit < 0)) goto done; - remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); - if (unlikely(idigit >= (1L << remaining_bits))) - goto raise_overflow; - val |= ((int) idigit) << bits; - } - if (!is_unsigned) { - if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) - goto raise_overflow; - if (is_negative) - val = ~val; - } - ret = 0; - done: - Py_XDECREF(shift); - Py_XDECREF(mask); - Py_XDECREF(stepval); -#endif - if (unlikely(ret)) - return (int) -1; - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to int"); - return (int) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to int"); - return (int) -1; -} - -/* FastTypeChecks */ -#if CYTHON_COMPILING_IN_CPYTHON -static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { - while (a) { - a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); - if (a == b) - return 1; - } - return b == &PyBaseObject_Type; -} -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { - PyObject *mro; - if (a == b) return 1; - mro = a->tp_mro; - if (likely(mro)) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) - return 1; - } - return 0; - } - return __Pyx_InBases(a, b); -} -static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { - PyObject *mro; - if (cls == a || cls == b) return 1; - mro = cls->tp_mro; - if (likely(mro)) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - PyObject *base = PyTuple_GET_ITEM(mro, i); - if (base == (PyObject *)a || base == (PyObject *)b) - return 1; - } - return 0; - } - return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); -} -static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { - if (exc_type1) { - return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); - } else { - return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); - } -} -static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - assert(PyExceptionClass_Check(exc_type)); - n = PyTuple_GET_SIZE(tuple); - for (i=0; i= 0x030b0000 - return Py_Version & ~0xFFUL; -#else - static unsigned long __Pyx_cached_runtime_version = 0; - if (__Pyx_cached_runtime_version == 0) { - const char* rt_version = Py_GetVersion(); - unsigned long version = 0; - unsigned long factor = 0x01000000UL; - unsigned int digit = 0; - int i = 0; - while (factor) { - while ('0' <= rt_version[i] && rt_version[i] <= '9') { - digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); - ++i; - } - version += factor * digit; - if (rt_version[i] != '.') - break; - digit = 0; - factor >>= 8; - ++i; - } - __Pyx_cached_runtime_version = version; - } - return __Pyx_cached_runtime_version; -#endif -} - -/* CheckBinaryVersion */ -static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { - const unsigned long MAJOR_MINOR = 0xFFFF0000UL; - if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) - return 0; - if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) - return 1; - { - char message[200]; - PyOS_snprintf(message, sizeof(message), - "compile time Python version %d.%d " - "of module '%.100s' " - "%s " - "runtime version %d.%d", - (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), - __Pyx_MODULE_NAME, - (allow_newer) ? "was newer than" : "does not match", - (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) - ); - return PyErr_WarnEx(NULL, message, 1); - } -} - -/* InitStrings */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry const *t, PyObject **target, const char* const* encoding_names) { - while (t->s) { - PyObject *str; - if (t->is_unicode) { - if (t->intern) { - str = PyUnicode_InternFromString(t->s); - } else if (t->encoding) { - str = PyUnicode_Decode(t->s, t->n - 1, encoding_names[t->encoding], NULL); - } else { - str = PyUnicode_FromStringAndSize(t->s, t->n - 1); - } - } else { - str = PyBytes_FromStringAndSize(t->s, t->n - 1); - } - if (!str) - return -1; - *target = str; - if (PyObject_Hash(str) == -1) - return -1; - ++t; - ++target; - } - return 0; -} - -#include -static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { - size_t len = strlen(s); - if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { - PyErr_SetString(PyExc_OverflowError, "byte string is too long"); - return -1; - } - return (Py_ssize_t) len; -} -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { - Py_ssize_t len = __Pyx_ssize_strlen(c_str); - if (unlikely(len < 0)) return NULL; - return __Pyx_PyUnicode_FromStringAndSize(c_str, len); -} -static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { - Py_ssize_t len = __Pyx_ssize_strlen(c_str); - if (unlikely(len < 0)) return NULL; - return PyByteArray_FromStringAndSize(c_str, len); -} -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { - Py_ssize_t ignore; - return __Pyx_PyObject_AsStringAndSize(o, &ignore); -} -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 -static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { - if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; -#if CYTHON_COMPILING_IN_LIMITED_API - { - const char* result; - Py_ssize_t unicode_length; - CYTHON_MAYBE_UNUSED_VAR(unicode_length); // only for __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - #if __PYX_LIMITED_VERSION_HEX < 0x030A0000 - if (unlikely(PyArg_Parse(o, "s#", &result, length) < 0)) return NULL; - #else - result = PyUnicode_AsUTF8AndSize(o, length); - #endif - #if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - unicode_length = PyUnicode_GetLength(o); - if (unlikely(unicode_length < 0)) return NULL; - if (unlikely(unicode_length != *length)) { - PyUnicode_AsASCIIString(o); - return NULL; - } - #endif - return result; - } -#else -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - if (likely(PyUnicode_IS_ASCII(o))) { - *length = PyUnicode_GET_LENGTH(o); - return PyUnicode_AsUTF8(o); - } else { - PyUnicode_AsASCIIString(o); - return NULL; - } -#else - return PyUnicode_AsUTF8AndSize(o, length); -#endif -#endif -} -#endif -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 - if (PyUnicode_Check(o)) { - return __Pyx_PyUnicode_AsStringAndSize(o, length); - } else -#endif - if (PyByteArray_Check(o)) { -#if (CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS) || (CYTHON_COMPILING_IN_PYPY && (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE))) - *length = PyByteArray_GET_SIZE(o); - return PyByteArray_AS_STRING(o); -#else - *length = PyByteArray_Size(o); - if (*length == -1) return NULL; - return PyByteArray_AsString(o); -#endif - } else - { - char* result; - int r = PyBytes_AsStringAndSize(o, &result, length); - if (unlikely(r < 0)) { - return NULL; - } else { - return result; - } - } -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - int is_true = x == Py_True; - if (is_true | (x == Py_False) | (x == Py_None)) return is_true; - else return PyObject_IsTrue(x); -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { - int retval; - if (unlikely(!x)) return -1; - retval = __Pyx_PyObject_IsTrue(x); - Py_DECREF(x); - return retval; -} -static PyObject* __Pyx_PyNumber_LongWrongResultType(PyObject* result) { - __Pyx_TypeName result_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(result)); - if (PyLong_Check(result)) { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " - "The ability to return an instance of a strict subclass of int is deprecated, " - "and may be removed in a future version of Python.", - result_type_name)) { - __Pyx_DECREF_TypeName(result_type_name); - Py_DECREF(result); - return NULL; - } - __Pyx_DECREF_TypeName(result_type_name); - return result; - } - PyErr_Format(PyExc_TypeError, - "__int__ returned non-int (type " __Pyx_FMT_TYPENAME ")", - result_type_name); - __Pyx_DECREF_TypeName(result_type_name); - Py_DECREF(result); - return NULL; -} -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x) { -#if CYTHON_USE_TYPE_SLOTS - PyNumberMethods *m; -#endif - PyObject *res = NULL; - if (likely(PyLong_Check(x))) - return __Pyx_NewRef(x); -#if CYTHON_USE_TYPE_SLOTS - m = Py_TYPE(x)->tp_as_number; - if (likely(m && m->nb_int)) { - res = m->nb_int(x); - } -#else - if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { - res = PyNumber_Long(x); - } -#endif - if (likely(res)) { - if (unlikely(!PyLong_CheckExact(res))) { - return __Pyx_PyNumber_LongWrongResultType(res); - } - } - else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "an integer is required"); - } - return res; -} -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject *x; - if (likely(PyLong_CheckExact(b))) { - #if CYTHON_USE_PYLONG_INTERNALS - if (likely(__Pyx_PyLong_IsCompact(b))) { - return __Pyx_PyLong_CompactValue(b); - } else { - const digit* digits = __Pyx_PyLong_Digits(b); - const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); - switch (size) { - case 2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - } - } - #endif - return PyLong_AsSsize_t(b); - } - x = PyNumber_Index(b); - if (!x) return -1; - ival = PyLong_AsSsize_t(x); - Py_DECREF(x); - return ival; -} -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { - if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { - return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); - } else { - Py_ssize_t ival; - PyObject *x; - x = PyNumber_Index(o); - if (!x) return -1; - ival = PyLong_AsLong(x); - Py_DECREF(x); - return ival; - } -} -static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b) { - CYTHON_UNUSED_VAR(b); - return __Pyx_NewRef(Py_None); -} -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); -} -static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t ival) { - return PyLong_FromSize_t(ival); -} - - -/* MultiPhaseInitModuleState */ -#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE -#ifndef CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -#if (CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX >= 0x030C0000) - #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 1 -#else - #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 0 -#endif -#endif -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE && !CYTHON_ATOMICS -#error "Module state with PEP489 requires atomics. Currently that's one of\ - C11, C++11, gcc atomic intrinsics or MSVC atomic intrinsics" -#endif -#if !CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -#define __Pyx_ModuleStateLookup_Lock() -#define __Pyx_ModuleStateLookup_Unlock() -#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d0000 -static PyMutex __Pyx_ModuleStateLookup_mutex = {0}; -#define __Pyx_ModuleStateLookup_Lock() PyMutex_Lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() PyMutex_Unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(__cplusplus) && __cplusplus >= 201103L -#include -static std::mutex __Pyx_ModuleStateLookup_mutex; -#define __Pyx_ModuleStateLookup_Lock() __Pyx_ModuleStateLookup_mutex.lock() -#define __Pyx_ModuleStateLookup_Unlock() __Pyx_ModuleStateLookup_mutex.unlock() -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201112L) && !defined(__STDC_NO_THREADS__) -#include -static mtx_t __Pyx_ModuleStateLookup_mutex; -static once_flag __Pyx_ModuleStateLookup_mutex_once_flag = ONCE_FLAG_INIT; -static void __Pyx_ModuleStateLookup_initialize_mutex(void) { - mtx_init(&__Pyx_ModuleStateLookup_mutex, mtx_plain); -} -#define __Pyx_ModuleStateLookup_Lock()\ - call_once(&__Pyx_ModuleStateLookup_mutex_once_flag, __Pyx_ModuleStateLookup_initialize_mutex);\ - mtx_lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() mtx_unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(HAVE_PTHREAD_H) -#include -static pthread_mutex_t __Pyx_ModuleStateLookup_mutex = PTHREAD_MUTEX_INITIALIZER; -#define __Pyx_ModuleStateLookup_Lock() pthread_mutex_lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() pthread_mutex_unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(_WIN32) -#include // synchapi.h on its own doesn't work -static SRWLOCK __Pyx_ModuleStateLookup_mutex = SRWLOCK_INIT; -#define __Pyx_ModuleStateLookup_Lock() AcquireSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() ReleaseSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) -#else -#error "No suitable lock available for CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE.\ - Requires C standard >= C11, or C++ standard >= C++11,\ - or pthreads, or the Windows 32 API, or Python >= 3.13." -#endif -typedef struct { - int64_t id; - PyObject *module; -} __Pyx_InterpreterIdAndModule; -typedef struct { - char interpreter_id_as_index; - Py_ssize_t count; - Py_ssize_t allocated; - __Pyx_InterpreterIdAndModule table[1]; -} __Pyx_ModuleStateLookupData; -#define __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE 32 -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static __pyx_atomic_int_type __Pyx_ModuleStateLookup_read_counter = 0; -#endif -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static __pyx_atomic_ptr_type __Pyx_ModuleStateLookup_data = 0; -#else -static __Pyx_ModuleStateLookupData* __Pyx_ModuleStateLookup_data = NULL; -#endif -static __Pyx_InterpreterIdAndModule* __Pyx_State_FindModuleStateLookupTableLowerBound( - __Pyx_InterpreterIdAndModule* table, - Py_ssize_t count, - int64_t interpreterId) { - __Pyx_InterpreterIdAndModule* begin = table; - __Pyx_InterpreterIdAndModule* end = begin + count; - if (begin->id == interpreterId) { - return begin; - } - while ((end - begin) > __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { - __Pyx_InterpreterIdAndModule* halfway = begin + (end - begin)/2; - if (halfway->id == interpreterId) { - return halfway; - } - if (halfway->id < interpreterId) { - begin = halfway; - } else { - end = halfway; - } - } - for (; begin < end; ++begin) { - if (begin->id >= interpreterId) return begin; - } - return begin; -} -static PyObject *__Pyx_State_FindModule(CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return NULL; -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData* data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); - { - __pyx_atomic_incr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); - if (likely(data)) { - __Pyx_ModuleStateLookupData* new_data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_acquire(&__Pyx_ModuleStateLookup_data); - if (likely(data == new_data)) { - goto read_finished; - } - } - __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); - __Pyx_ModuleStateLookup_Lock(); - __pyx_atomic_incr_relaxed(&__Pyx_ModuleStateLookup_read_counter); - data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); - __Pyx_ModuleStateLookup_Unlock(); - } - read_finished:; -#else - __Pyx_ModuleStateLookupData* data = __Pyx_ModuleStateLookup_data; -#endif - __Pyx_InterpreterIdAndModule* found = NULL; - if (unlikely(!data)) goto end; - if (data->interpreter_id_as_index) { - if (interpreter_id < data->count) { - found = data->table+interpreter_id; - } - } else { - found = __Pyx_State_FindModuleStateLookupTableLowerBound( - data->table, data->count, interpreter_id); - } - end: - { - PyObject *result=NULL; - if (found && found->id == interpreter_id) { - result = found->module; - } -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); -#endif - return result; - } -} -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static void __Pyx_ModuleStateLookup_wait_until_no_readers(void) { - while (__pyx_atomic_load(&__Pyx_ModuleStateLookup_read_counter) != 0); -} -#else -#define __Pyx_ModuleStateLookup_wait_until_no_readers() -#endif -static int __Pyx_State_AddModuleInterpIdAsIndex(__Pyx_ModuleStateLookupData **old_data, PyObject* module, int64_t interpreter_id) { - Py_ssize_t to_allocate = (*old_data)->allocated; - while (to_allocate <= interpreter_id) { - if (to_allocate == 0) to_allocate = 1; - else to_allocate *= 2; - } - __Pyx_ModuleStateLookupData *new_data = *old_data; - if (to_allocate != (*old_data)->allocated) { - new_data = (__Pyx_ModuleStateLookupData *)realloc( - *old_data, - sizeof(__Pyx_ModuleStateLookupData)+(to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); - if (!new_data) { - PyErr_NoMemory(); - return -1; - } - for (Py_ssize_t i = new_data->allocated; i < to_allocate; ++i) { - new_data->table[i].id = i; - new_data->table[i].module = NULL; - } - new_data->allocated = to_allocate; - } - new_data->table[interpreter_id].module = module; - if (new_data->count < interpreter_id+1) { - new_data->count = interpreter_id+1; - } - *old_data = new_data; - return 0; -} -static void __Pyx_State_ConvertFromInterpIdAsIndex(__Pyx_ModuleStateLookupData *data) { - __Pyx_InterpreterIdAndModule *read = data->table; - __Pyx_InterpreterIdAndModule *write = data->table; - __Pyx_InterpreterIdAndModule *end = read + data->count; - for (; readmodule) { - write->id = read->id; - write->module = read->module; - ++write; - } - } - data->count = write - data->table; - for (; writeid = 0; - write->module = NULL; - } - data->interpreter_id_as_index = 0; -} -static int __Pyx_State_AddModule(PyObject* module, CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return -1; - int result = 0; - __Pyx_ModuleStateLookup_Lock(); -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData *old_data = (__Pyx_ModuleStateLookupData *) - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); -#else - __Pyx_ModuleStateLookupData *old_data = __Pyx_ModuleStateLookup_data; -#endif - __Pyx_ModuleStateLookupData *new_data = old_data; - if (!new_data) { - new_data = (__Pyx_ModuleStateLookupData *)calloc(1, sizeof(__Pyx_ModuleStateLookupData)); - if (!new_data) { - result = -1; - PyErr_NoMemory(); - goto end; - } - new_data->allocated = 1; - new_data->interpreter_id_as_index = 1; - } - __Pyx_ModuleStateLookup_wait_until_no_readers(); - if (new_data->interpreter_id_as_index) { - if (interpreter_id < __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { - result = __Pyx_State_AddModuleInterpIdAsIndex(&new_data, module, interpreter_id); - goto end; - } - __Pyx_State_ConvertFromInterpIdAsIndex(new_data); - } - { - Py_ssize_t insert_at = 0; - { - __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( - new_data->table, new_data->count, interpreter_id); - assert(lower_bound); - insert_at = lower_bound - new_data->table; - if (unlikely(insert_at < new_data->count && lower_bound->id == interpreter_id)) { - lower_bound->module = module; - goto end; // already in table, nothing more to do - } - } - if (new_data->count+1 >= new_data->allocated) { - Py_ssize_t to_allocate = (new_data->count+1)*2; - new_data = - (__Pyx_ModuleStateLookupData*)realloc( - new_data, - sizeof(__Pyx_ModuleStateLookupData) + - (to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); - if (!new_data) { - result = -1; - new_data = old_data; - PyErr_NoMemory(); - goto end; - } - new_data->allocated = to_allocate; - } - ++new_data->count; - int64_t last_id = interpreter_id; - PyObject *last_module = module; - for (Py_ssize_t i=insert_at; icount; ++i) { - int64_t current_id = new_data->table[i].id; - new_data->table[i].id = last_id; - last_id = current_id; - PyObject *current_module = new_data->table[i].module; - new_data->table[i].module = last_module; - last_module = current_module; - } - } - end: -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, new_data); -#else - __Pyx_ModuleStateLookup_data = new_data; -#endif - __Pyx_ModuleStateLookup_Unlock(); - return result; -} -static int __Pyx_State_RemoveModule(CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return -1; - __Pyx_ModuleStateLookup_Lock(); -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData *data = (__Pyx_ModuleStateLookupData *) - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); -#else - __Pyx_ModuleStateLookupData *data = __Pyx_ModuleStateLookup_data; -#endif - if (data->interpreter_id_as_index) { - if (interpreter_id < data->count) { - data->table[interpreter_id].module = NULL; - } - goto done; - } - { - __Pyx_ModuleStateLookup_wait_until_no_readers(); - __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( - data->table, data->count, interpreter_id); - if (!lower_bound) goto done; - if (lower_bound->id != interpreter_id) goto done; - __Pyx_InterpreterIdAndModule *end = data->table+data->count; - for (;lower_boundid = (lower_bound+1)->id; - lower_bound->module = (lower_bound+1)->module; - } - } - --data->count; - if (data->count == 0) { - free(data); - data = NULL; - } - done: -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, data); -#else - __Pyx_ModuleStateLookup_data = data; -#endif - __Pyx_ModuleStateLookup_Unlock(); - return 0; -} -#endif - -/* #### Code section: utility_code_pragmas_end ### */ -#ifdef _MSC_VER -#pragma warning( pop ) -#endif - - - -/* #### Code section: end ### */ -#endif /* Py_PYTHON_H */ diff --git a/epanet/epanet.c b/epanet/epanet.c deleted file mode 100644 index 0ef378b..0000000 --- a/epanet/epanet.c +++ /dev/null @@ -1,21700 +0,0 @@ -/* Generated by Cython 3.1.0 */ - -/* BEGIN: Cython Metadata -{ - "distutils": { - "name": "epanet.epanet", - "sources": [ - "epanet\\epanet.py" - ] - }, - "module_name": "epanet.epanet" -} -END: Cython Metadata */ - -#ifndef PY_SSIZE_T_CLEAN -#define PY_SSIZE_T_CLEAN -#endif /* PY_SSIZE_T_CLEAN */ -/* InitLimitedAPI */ -#if defined(Py_LIMITED_API) && !defined(CYTHON_LIMITED_API) - #define CYTHON_LIMITED_API 1 -#endif - -#include "Python.h" -#ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. -#elif PY_VERSION_HEX < 0x03080000 - #error Cython requires Python 3.8+. -#else -#define __PYX_ABI_VERSION "3_1_0" -#define CYTHON_HEX_VERSION 0x030100F0 -#define CYTHON_FUTURE_DIVISION 1 -/* CModulePreamble */ -#include -#ifndef offsetof - #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) -#endif -#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __fastcall - #define __fastcall - #endif -#endif -#ifndef DL_IMPORT - #define DL_IMPORT(t) t -#endif -#ifndef DL_EXPORT - #define DL_EXPORT(t) t -#endif -#define __PYX_COMMA , -#ifndef HAVE_LONG_LONG - #define HAVE_LONG_LONG -#endif -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#ifndef Py_HUGE_VAL - #define Py_HUGE_VAL HUGE_VAL -#endif -#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX -#if defined(GRAALVM_PYTHON) - /* For very preliminary testing purposes. Most variables are set the same as PyPy. - The existence of this section does not imply that anything works or is even tested */ - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 1 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 0 - #undef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #undef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 1 - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #undef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 0 - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #undef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #undef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #undef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 1 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#elif defined(PYPY_VERSION) - #define CYTHON_COMPILING_IN_PYPY 1 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 0 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #ifndef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #endif - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #undef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 1 - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #ifndef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 1 - #endif - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #if PY_VERSION_HEX < 0x03090000 - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 0 - #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #undef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE (PYPY_VERSION_NUM >= 0x07030C00) - #endif - #undef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC (PYPY_VERSION_NUM >= 0x07031100) - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#elif defined(CYTHON_LIMITED_API) - #ifdef Py_LIMITED_API - #undef __PYX_LIMITED_VERSION_HEX - #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API - #endif - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 1 - #define CYTHON_COMPILING_IN_GRAAL 0 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_CLINE_IN_TRACEBACK - #define CYTHON_CLINE_IN_TRACEBACK 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 0 - #undef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 1 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #ifndef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #endif - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #ifndef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 - #endif - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #undef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 0 - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #ifndef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #endif - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #endif - #ifndef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND (__PYX_LIMITED_VERSION_HEX >= 0x030A0000) - #endif - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#else - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 1 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 0 - #ifdef Py_GIL_DISABLED - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 1 - #else - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #endif - #if PY_VERSION_HEX < 0x030A0000 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #elif !defined(CYTHON_USE_TYPE_SLOTS) - #define CYTHON_USE_TYPE_SLOTS 1 - #endif - #ifndef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #endif - #ifndef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 1 - #endif - #ifndef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #elif !defined(CYTHON_USE_PYLIST_INTERNALS) - #define CYTHON_USE_PYLIST_INTERNALS 1 - #endif - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) - #define CYTHON_USE_UNICODE_WRITER 1 - #endif - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #elif !defined(CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS) - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 - #endif - #ifndef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 1 - #endif - #ifndef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 1 - #endif - #ifndef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 1 - #endif - #ifndef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #elif !defined(CYTHON_FAST_GIL) - #define CYTHON_FAST_GIL (PY_VERSION_HEX < 0x030C00A6) - #endif - #ifndef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 1 - #endif - #ifndef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 1 - #endif - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #ifndef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #endif - #ifndef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING (PY_VERSION_HEX >= 0x030d00B1) - #endif - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 1 - #endif - #ifndef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #elif !defined(CYTHON_USE_DICT_VERSIONS) - #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5 && !CYTHON_USE_MODULE_STATE) - #endif - #ifndef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 1 - #endif - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 - #endif - #ifndef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS (!CYTHON_COMPILING_IN_CPYTHON_FREETHREADING) - #endif -#endif -#ifndef CYTHON_FAST_PYCCALL -#define CYTHON_FAST_PYCCALL CYTHON_FAST_PYCALL -#endif -#ifndef CYTHON_VECTORCALL -#if CYTHON_COMPILING_IN_LIMITED_API -#define CYTHON_VECTORCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) -#else -#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) -#endif -#endif -#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) -#if CYTHON_USE_PYLONG_INTERNALS - #undef SHIFT - #undef BASE - #undef MASK - #ifdef SIZEOF_VOID_P - enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; - #endif -#endif -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif -#ifndef __has_cpp_attribute - #define __has_cpp_attribute(x) 0 -#endif -#ifndef CYTHON_RESTRICT - #if defined(__GNUC__) - #define CYTHON_RESTRICT __restrict__ - #elif defined(_MSC_VER) && _MSC_VER >= 1400 - #define CYTHON_RESTRICT __restrict - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_RESTRICT restrict - #else - #define CYTHON_RESTRICT - #endif -#endif -#ifndef CYTHON_UNUSED - #if defined(__cplusplus) - /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 - * but leads to warnings with -pedantic, since it is a C++17 feature */ - #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) - #if __has_cpp_attribute(maybe_unused) - #define CYTHON_UNUSED [[maybe_unused]] - #endif - #endif - #endif -#endif -#ifndef CYTHON_UNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_UNUSED_VAR -# if defined(__cplusplus) - template void CYTHON_UNUSED_VAR( const T& ) { } -# else -# define CYTHON_UNUSED_VAR(x) (void)(x) -# endif -#endif -#ifndef CYTHON_MAYBE_UNUSED_VAR - #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) -#endif -#ifndef CYTHON_NCP_UNUSED -# if CYTHON_COMPILING_IN_CPYTHON -# define CYTHON_NCP_UNUSED -# else -# define CYTHON_NCP_UNUSED CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_USE_CPP_STD_MOVE - #if defined(__cplusplus) && (\ - __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) - #define CYTHON_USE_CPP_STD_MOVE 1 - #else - #define CYTHON_USE_CPP_STD_MOVE 0 - #endif -#endif -#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) -#ifdef _MSC_VER - #ifndef _MSC_STDINT_H_ - #if _MSC_VER < 1300 - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; - #else - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - #endif - #endif - #if _MSC_VER < 1300 - #ifdef _WIN64 - typedef unsigned long long __pyx_uintptr_t; - #else - typedef unsigned int __pyx_uintptr_t; - #endif - #else - #ifdef _WIN64 - typedef unsigned __int64 __pyx_uintptr_t; - #else - typedef unsigned __int32 __pyx_uintptr_t; - #endif - #endif -#else - #include - typedef uintptr_t __pyx_uintptr_t; -#endif -#ifndef CYTHON_FALLTHROUGH - #if defined(__cplusplus) - /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 - * but leads to warnings with -pedantic, since it is a C++17 feature */ - #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) - #if __has_cpp_attribute(fallthrough) - #define CYTHON_FALLTHROUGH [[fallthrough]] - #endif - #endif - #ifndef CYTHON_FALLTHROUGH - #if __has_cpp_attribute(clang::fallthrough) - #define CYTHON_FALLTHROUGH [[clang::fallthrough]] - #elif __has_cpp_attribute(gnu::fallthrough) - #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] - #endif - #endif - #endif - #ifndef CYTHON_FALLTHROUGH - #if __has_attribute(fallthrough) - #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) - #else - #define CYTHON_FALLTHROUGH - #endif - #endif - #if defined(__clang__) && defined(__apple_build_version__) - #if __apple_build_version__ < 7000000 - #undef CYTHON_FALLTHROUGH - #define CYTHON_FALLTHROUGH - #endif - #endif -#endif -#ifndef Py_UNREACHABLE - #define Py_UNREACHABLE() assert(0); abort() -#endif -#ifdef __cplusplus - template - struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; - #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) -#else - #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) -#endif -#if CYTHON_COMPILING_IN_PYPY == 1 - #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) -#else - #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) -#endif -#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) - -/* CInitCode */ -#ifndef CYTHON_INLINE - #if defined(__clang__) - #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) - #elif defined(__GNUC__) - #define CYTHON_INLINE __inline__ - #elif defined(_MSC_VER) - #define CYTHON_INLINE __inline - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_INLINE inline - #else - #define CYTHON_INLINE - #endif -#endif - -/* PythonCompatibility */ -#define __PYX_BUILD_PY_SSIZE_T "n" -#define CYTHON_FORMAT_SSIZE_T "z" -#define __Pyx_BUILTIN_MODULE_NAME "builtins" -#define __Pyx_DefaultClassType PyType_Type -#if CYTHON_COMPILING_IN_LIMITED_API - #ifndef CO_OPTIMIZED - static int CO_OPTIMIZED; - #endif - #ifndef CO_NEWLOCALS - static int CO_NEWLOCALS; - #endif - #ifndef CO_VARARGS - static int CO_VARARGS; - #endif - #ifndef CO_VARKEYWORDS - static int CO_VARKEYWORDS; - #endif - #ifndef CO_ASYNC_GENERATOR - static int CO_ASYNC_GENERATOR; - #endif - #ifndef CO_GENERATOR - static int CO_GENERATOR; - #endif - #ifndef CO_COROUTINE - static int CO_COROUTINE; - #endif -#else - #ifndef CO_COROUTINE - #define CO_COROUTINE 0x80 - #endif - #ifndef CO_ASYNC_GENERATOR - #define CO_ASYNC_GENERATOR 0x200 - #endif -#endif -static int __Pyx_init_co_variables(void); -#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) - #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) -#else - #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) - #define __Pyx_Py_Is(x, y) Py_Is(x, y) -#else - #define __Pyx_Py_Is(x, y) ((x) == (y)) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) - #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) -#else - #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) - #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) -#else - #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) - #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) -#else - #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) -#endif -#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) -#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) -#else - #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) -#endif -#ifndef Py_TPFLAGS_CHECKTYPES - #define Py_TPFLAGS_CHECKTYPES 0 -#endif -#ifndef Py_TPFLAGS_HAVE_INDEX - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#ifndef Py_TPFLAGS_HAVE_NEWBUFFER - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif -#ifndef Py_TPFLAGS_HAVE_FINALIZE - #define Py_TPFLAGS_HAVE_FINALIZE 0 -#endif -#ifndef Py_TPFLAGS_SEQUENCE - #define Py_TPFLAGS_SEQUENCE 0 -#endif -#ifndef Py_TPFLAGS_MAPPING - #define Py_TPFLAGS_MAPPING 0 -#endif -#ifndef METH_STACKLESS - #define METH_STACKLESS 0 -#endif -#ifndef METH_FASTCALL - #ifndef METH_FASTCALL - #define METH_FASTCALL 0x80 - #endif - typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); - typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames); -#else - #if PY_VERSION_HEX >= 0x030d00A4 - # define __Pyx_PyCFunctionFast PyCFunctionFast - # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords - #else - # define __Pyx_PyCFunctionFast _PyCFunctionFast - # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords - #endif -#endif -#if CYTHON_METH_FASTCALL - #define __Pyx_METH_FASTCALL METH_FASTCALL - #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast - #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords -#else - #define __Pyx_METH_FASTCALL METH_VARARGS - #define __Pyx_PyCFunction_FastCall PyCFunction - #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords -#endif -#if CYTHON_VECTORCALL - #define __pyx_vectorcallfunc vectorcallfunc - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET - #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) -#elif CYTHON_BACKPORT_VECTORCALL - typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, - size_t nargsf, PyObject *kwnames); - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) - #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) -#else - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 - #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) -#endif -#if PY_VERSION_HEX >= 0x030900B1 -#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) -#else -#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) -#endif -#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) -#elif !CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) -#endif -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) -static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { - return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; -} -#endif -static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void (*cfunc)(void)) { -#if CYTHON_COMPILING_IN_LIMITED_API - return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; -#else - return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; -#endif -} -#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) -#if __PYX_LIMITED_VERSION_HEX < 0x03090000 - #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) - typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); -#else - #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) - #define __Pyx_PyCMethod PyCMethod -#endif -#ifndef METH_METHOD - #define METH_METHOD 0x200 -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) - #define PyObject_Malloc(s) PyMem_Malloc(s) - #define PyObject_Free(p) PyMem_Free(p) - #define PyObject_Realloc(p) PyMem_Realloc(p) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) -#elif CYTHON_COMPILING_IN_GRAAL - #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) _PyFrame_SetLineNumber((frame), (lineno)) -#else - #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyThreadState_Current PyThreadState_Get() -#elif !CYTHON_FAST_THREAD_STATE - #define __Pyx_PyThreadState_Current PyThreadState_GET() -#elif PY_VERSION_HEX >= 0x030d00A1 - #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() -#else - #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() -#endif -#if CYTHON_USE_MODULE_STATE -static CYTHON_INLINE void *__Pyx__PyModule_GetState(PyObject *op) -{ - void *result; - result = PyModule_GetState(op); - if (!result) - Py_FatalError("Couldn't find the module state"); - return result; -} -#define __Pyx_PyModule_GetState(o) (__pyx_mstatetype *)__Pyx__PyModule_GetState(o) -#else -#define __Pyx_PyModule_GetState(op) ((void)op,__pyx_mstate_global) -#endif -#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE((PyObject *) obj), name, func_ctype) -#define __Pyx_PyObject_TryGetSlot(obj, name, func_ctype) __Pyx_PyType_TryGetSlot(Py_TYPE(obj), name, func_ctype) -#define __Pyx_PyObject_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(Py_TYPE(obj), sub, name, func_ctype) -#define __Pyx_PyObject_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSubSlot(Py_TYPE(obj), sub, name, func_ctype) -#if CYTHON_USE_TYPE_SLOTS - #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) - #define __Pyx_PyType_TryGetSlot(type, name, func_ctype) __Pyx_PyType_GetSlot(type, name, func_ctype) - #define __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) (((type)->sub) ? ((type)->sub->name) : NULL) - #define __Pyx_PyType_TryGetSubSlot(type, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) -#else - #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) - #define __Pyx_PyType_TryGetSlot(type, name, func_ctype)\ - ((__PYX_LIMITED_VERSION_HEX >= 0x030A0000 ||\ - (PyType_GetFlags(type) & Py_TPFLAGS_HEAPTYPE) || __Pyx_get_runtime_version() >= 0x030A0000) ?\ - __Pyx_PyType_GetSlot(type, name, func_ctype) : NULL) - #define __Pyx_PyType_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSlot(obj, name, func_ctype) - #define __Pyx_PyType_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSlot(obj, name, func_ctype) -#endif -#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) -#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) -#else -#define __Pyx_PyDict_NewPresized(n) PyDict_New() -#endif -#define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) -#define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) -#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_UNICODE_INTERNALS -#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) -static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { - PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); - if (res == NULL) PyErr_Clear(); - return res; -} -#elif !CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000 -#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError -#define __Pyx_PyDict_GetItemStr PyDict_GetItem -#else -static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { -#if CYTHON_COMPILING_IN_PYPY - return PyDict_GetItem(dict, name); -#else - PyDictEntry *ep; - PyDictObject *mp = (PyDictObject*) dict; - long hash = ((PyStringObject *) name)->ob_shash; - assert(hash != -1); - ep = (mp->ma_lookup)(mp, name, hash); - if (ep == NULL) { - return NULL; - } - return ep->me_value; -#endif -} -#define __Pyx_PyDict_GetItemStr PyDict_GetItem -#endif -#if CYTHON_USE_TYPE_SLOTS - #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) - #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) -#else - #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) - #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) -#endif -#define __Pyx_PyObject_GetIterNextFunc(iterator) __Pyx_PyObject_GetSlot(iterator, tp_iternext, iternextfunc) -#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 -#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ - PyTypeObject *type = Py_TYPE((PyObject*)obj);\ - assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ - PyObject_GC_Del(obj);\ - Py_DECREF(type);\ -} -#else -#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyUnicode_READY(op) (0) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) - #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) - #define __Pyx_PyUnicode_DATA(u) ((void*)u) - #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) -#else - #if PY_VERSION_HEX >= 0x030C0000 - #define __Pyx_PyUnicode_READY(op) (0) - #else - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) - #endif - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) - #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) - #if PY_VERSION_HEX >= 0x030C0000 - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) - #else - #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) - #endif - #endif -#endif -#if CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) -#else - #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ - PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) -#endif -#if CYTHON_COMPILING_IN_PYPY - #if !defined(PyUnicode_DecodeUnicodeEscape) - #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) - #endif - #if !defined(PyUnicode_Contains) - #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) - #endif - #if !defined(PyByteArray_Check) - #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) - #endif - #if !defined(PyObject_Format) - #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) - #endif -#endif -#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) -#if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_PySequence_ListKeepNew(obj)\ - (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) -#else - #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) -#endif -#ifndef PySet_CheckExact - #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) -#endif -#if PY_VERSION_HEX >= 0x030900A4 - #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -#else - #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS || !CYTHON_ASSUME_SAFE_MACROS - #if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - #define __Pyx_PyList_GetItemRef(o, i) PyList_GetItemRef(o, i) - #else - #define __Pyx_PyList_GetItemRef(o, i) PySequence_GetItem(o, i) - #endif -#else - #define __Pyx_PyList_GetItemRef(o, i) __Pyx_NewRef(PyList_GET_ITEM(o, i)) -#endif -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 -#define __Pyx_PyDict_GetItemRef(dict, key, result) PyDict_GetItemRef(dict, key, result) -#elif CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS -static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { - *result = PyObject_GetItem(dict, key); - if (*result == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - return 0; - } - return -1; - } - return 1; -} -#else -static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { - *result = PyDict_GetItemWithError(dict, key); - if (*result == NULL) { - return PyErr_Occurred() ? -1 : 0; - } - Py_INCREF(*result); - return 1; -} -#endif -#if defined(CYTHON_DEBUG_VISIT_CONST) && CYTHON_DEBUG_VISIT_CONST - #define __Pyx_VISIT_CONST(obj) Py_VISIT(obj) -#else - #define __Pyx_VISIT_CONST(obj) -#endif -#if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) - #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GET_ITEM(o, i) - #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) - #define __Pyx_PyList_GET_ITEM(o, i) PyList_GET_ITEM(o, i) -#else - #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) - #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) - #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) - #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GetItem(o, i) - #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) - #define __Pyx_PyList_GET_ITEM(o, i) PyList_GetItem(o, i) -#endif -#if CYTHON_ASSUME_SAFE_SIZE - #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) - #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) - #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) - #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) - #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) - #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GET_LENGTH(o) -#else - #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) - #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) - #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) - #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) - #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) - #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GetLength(o) -#endif -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) -#else - static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { - PyObject *module = PyImport_AddModule(name); - Py_XINCREF(module); - return module; - } -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_InternFromString) - #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) -#endif -#define __Pyx_PyLong_FromHash_t PyLong_FromSsize_t -#define __Pyx_PyLong_AsHash_t __Pyx_PyIndex_AsSsize_t -#if __PYX_LIMITED_VERSION_HEX >= 0x030A0000 - #define __Pyx_PySendResult PySendResult -#else - typedef enum { - PYGEN_RETURN = 0, - PYGEN_ERROR = -1, - PYGEN_NEXT = 1, - } __Pyx_PySendResult; -#endif -#if CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX < 0x030A00A3 - typedef __Pyx_PySendResult (*__Pyx_pyiter_sendfunc)(PyObject *iter, PyObject *value, PyObject **result); -#else - #define __Pyx_pyiter_sendfunc sendfunc -#endif -#if !CYTHON_USE_AM_SEND -#define __PYX_HAS_PY_AM_SEND 0 -#elif __PYX_LIMITED_VERSION_HEX >= 0x030A0000 -#define __PYX_HAS_PY_AM_SEND 1 -#else -#define __PYX_HAS_PY_AM_SEND 2 // our own backported implementation -#endif -#if __PYX_HAS_PY_AM_SEND < 2 - #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods -#else - typedef struct { - unaryfunc am_await; - unaryfunc am_aiter; - unaryfunc am_anext; - __Pyx_pyiter_sendfunc am_send; - } __Pyx_PyAsyncMethodsStruct; - #define __Pyx_SlotTpAsAsync(s) ((PyAsyncMethods*)(s)) -#endif -#if CYTHON_USE_AM_SEND && PY_VERSION_HEX < 0x030A00F0 - #define __Pyx_TPFLAGS_HAVE_AM_SEND (1UL << 21) -#else - #define __Pyx_TPFLAGS_HAVE_AM_SEND (0) -#endif -#if PY_VERSION_HEX >= 0x03090000 -#define __Pyx_PyInterpreterState_Get() PyInterpreterState_Get() -#else -#define __Pyx_PyInterpreterState_Get() PyThreadState_Get()->interp -#endif -#if CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030A0000 -#ifdef __cplusplus -extern "C" -#endif -PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize); -#endif -#if CYTHON_COMPILING_IN_LIMITED_API -static int __Pyx_init_co_variable(PyObject *inspect, const char* name, int *write_to) { - int value; - PyObject *py_value = PyObject_GetAttrString(inspect, name); - if (!py_value) return 0; - value = (int) PyLong_AsLong(py_value); - Py_DECREF(py_value); - *write_to = value; - return value != -1 || !PyErr_Occurred(); -} -static int __Pyx_init_co_variables(void) { - PyObject *inspect; - int result; - inspect = PyImport_ImportModule("inspect"); - result = -#if !defined(CO_OPTIMIZED) - __Pyx_init_co_variable(inspect, "CO_OPTIMIZED", &CO_OPTIMIZED) && -#endif -#if !defined(CO_NEWLOCALS) - __Pyx_init_co_variable(inspect, "CO_NEWLOCALS", &CO_NEWLOCALS) && -#endif -#if !defined(CO_VARARGS) - __Pyx_init_co_variable(inspect, "CO_VARARGS", &CO_VARARGS) && -#endif -#if !defined(CO_VARKEYWORDS) - __Pyx_init_co_variable(inspect, "CO_VARKEYWORDS", &CO_VARKEYWORDS) && -#endif -#if !defined(CO_ASYNC_GENERATOR) - __Pyx_init_co_variable(inspect, "CO_ASYNC_GENERATOR", &CO_ASYNC_GENERATOR) && -#endif -#if !defined(CO_GENERATOR) - __Pyx_init_co_variable(inspect, "CO_GENERATOR", &CO_GENERATOR) && -#endif -#if !defined(CO_COROUTINE) - __Pyx_init_co_variable(inspect, "CO_COROUTINE", &CO_COROUTINE) && -#endif - 1; - Py_DECREF(inspect); - return result ? 0 : -1; -} -#else -static int __Pyx_init_co_variables(void) { - return 0; // It's a limited API-only feature -} -#endif - -/* MathInitCode */ -#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) - #ifndef _USE_MATH_DEFINES - #define _USE_MATH_DEFINES - #endif -#endif -#include -#ifdef NAN -#define __PYX_NAN() ((float) NAN) -#else -static CYTHON_INLINE float __PYX_NAN() { - float value; - memset(&value, 0xFF, sizeof(value)); - return value; -} -#endif -#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) -#define __Pyx_truncl trunc -#else -#define __Pyx_truncl truncl -#endif - -#ifndef CYTHON_CLINE_IN_TRACEBACK_RUNTIME -#define CYTHON_CLINE_IN_TRACEBACK_RUNTIME 0 -#endif -#ifndef CYTHON_CLINE_IN_TRACEBACK -#define CYTHON_CLINE_IN_TRACEBACK CYTHON_CLINE_IN_TRACEBACK_RUNTIME -#endif -#if CYTHON_CLINE_IN_TRACEBACK -#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; __pyx_clineno = __LINE__; (void) __pyx_clineno; } -#else -#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; (void) __pyx_clineno; } -#endif -#define __PYX_ERR(f_index, lineno, Ln_error) \ - { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - -#ifdef CYTHON_EXTERN_C - #undef __PYX_EXTERN_C - #define __PYX_EXTERN_C CYTHON_EXTERN_C -#elif defined(__PYX_EXTERN_C) - #ifdef _MSC_VER - #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") - #else - #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. - #endif -#else - #ifdef __cplusplus - #define __PYX_EXTERN_C extern "C" - #else - #define __PYX_EXTERN_C extern - #endif -#endif - -#define __PYX_HAVE__epanet__epanet -#define __PYX_HAVE_API__epanet__epanet -/* Early includes */ -#ifdef _OPENMP -#include -#endif /* _OPENMP */ - -#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) -#define CYTHON_WITHOUT_ASSERTIONS -#endif - -#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 -#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 -#define __PYX_DEFAULT_STRING_ENCODING "" -#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString -#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize -#define __Pyx_uchar_cast(c) ((unsigned char)c) -#define __Pyx_long_cast(x) ((long)x) -#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ - (sizeof(type) < sizeof(Py_ssize_t)) ||\ - (sizeof(type) > sizeof(Py_ssize_t) &&\ - likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX) &&\ - (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ - v == (type)PY_SSIZE_T_MIN))) ||\ - (sizeof(type) == sizeof(Py_ssize_t) &&\ - (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX))) ) -static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { - return (size_t) i < (size_t) limit; -} -#if defined (__cplusplus) && __cplusplus >= 201103L - #include - #define __Pyx_sst_abs(value) std::abs(value) -#elif SIZEOF_INT >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) abs(value) -#elif SIZEOF_LONG >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) labs(value) -#elif defined (_MSC_VER) - #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) -#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define __Pyx_sst_abs(value) llabs(value) -#elif defined (__GNUC__) - #define __Pyx_sst_abs(value) __builtin_llabs(value) -#else - #define __Pyx_sst_abs(value) ((value<0) ? -value : value) -#endif -static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); -static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); -#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) -#define __Pyx_PyBytes_FromString PyBytes_FromString -#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); -#if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyByteArray_AsString(s) PyByteArray_AS_STRING(s) -#else - #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AsString(s)) - #define __Pyx_PyByteArray_AsString(s) PyByteArray_AsString(s) -#endif -#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) -#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) -#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) -#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) -#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) -#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode -static CYTHON_INLINE PyObject *__Pyx_NewRef(PyObject *obj) { -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_NewRef) - return Py_NewRef(obj); -#else - Py_INCREF(obj); - return obj; -#endif -} -static CYTHON_INLINE PyObject *__Pyx_XNewRef(PyObject *obj) { -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_XNewRef) - return Py_XNewRef(obj); -#else - Py_XINCREF(obj); - return obj; -#endif -} -static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b); -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x); -#define __Pyx_PySequence_Tuple(obj)\ - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); -static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t); -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); -#if CYTHON_ASSUME_SAFE_MACROS -#define __Pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) -#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AS_DOUBLE(x) -#else -#define __Pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) -#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AsDouble(x) -#endif -#define __Pyx_PyFloat_AsFloat(x) ((float) __Pyx_PyFloat_AsDouble(x)) -#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) -#if CYTHON_USE_PYLONG_INTERNALS - #if PY_VERSION_HEX >= 0x030C00A7 - #ifndef _PyLong_SIGN_MASK - #define _PyLong_SIGN_MASK 3 - #endif - #ifndef _PyLong_NON_SIZE_BITS - #define _PyLong_NON_SIZE_BITS 3 - #endif - #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) - #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) - #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) - #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) - #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) - #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) - #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) - #define __Pyx_PyLong_SignedDigitCount(x)\ - ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) - #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) - #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) - #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) - #else - #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) - #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) - #endif - typedef Py_ssize_t __Pyx_compact_pylong; - typedef size_t __Pyx_compact_upylong; - #else - #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) - #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) - #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) - #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) - #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) - #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) - #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) - #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) - #define __Pyx_PyLong_CompactValue(x)\ - ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) - typedef sdigit __Pyx_compact_pylong; - typedef digit __Pyx_compact_upylong; - #endif - #if PY_VERSION_HEX >= 0x030C00A5 - #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) - #else - #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) - #endif -#endif -#if __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) -#elif __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeASCII(c_str, size, NULL) -#else - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) -#endif - - -/* Test for GCC > 2.95 */ -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) - #define likely(x) __builtin_expect(!!(x), 1) - #define unlikely(x) __builtin_expect(!!(x), 0) -#else /* !__GNUC__ or GCC < 2.95 */ - #define likely(x) (x) - #define unlikely(x) (x) -#endif /* __GNUC__ */ -/* PretendToInitialize */ -#ifdef __cplusplus -#include -template -static void __Pyx_pretend_to_initialize(T* ptr) { -#if __cplusplus > 201103L - if ((std::is_trivially_default_constructible::value)) -#endif - *ptr = T(); - (void)ptr; -} -#else -static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } -#endif - - -#if !CYTHON_USE_MODULE_STATE -static PyObject *__pyx_m = NULL; -#endif -static int __pyx_lineno; -static int __pyx_clineno = 0; -static const char * const __pyx_cfilenm = __FILE__; -static const char *__pyx_filename; - -/* #### Code section: filename_table ### */ - -static const char* const __pyx_f[] = { - "epanet/epanet.py", -}; -/* #### Code section: utility_code_proto_before_types ### */ -/* Atomics.proto */ -#include -#ifndef CYTHON_ATOMICS - #define CYTHON_ATOMICS 1 -#endif -#define __PYX_CYTHON_ATOMICS_ENABLED() CYTHON_ATOMICS -#define __PYX_GET_CYTHON_COMPILING_IN_CPYTHON_FREETHREADING() CYTHON_COMPILING_IN_CPYTHON_FREETHREADING -#define __pyx_atomic_int_type int -#define __pyx_nonatomic_int_type int -#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ - (__STDC_VERSION__ >= 201112L) &&\ - !defined(__STDC_NO_ATOMICS__)) - #include -#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ - (__cplusplus >= 201103L) ||\ - (defined(_MSC_VER) && _MSC_VER >= 1700))) - #include -#endif -#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ - (__STDC_VERSION__ >= 201112L) &&\ - !defined(__STDC_NO_ATOMICS__) &&\ - ATOMIC_INT_LOCK_FREE == 2) - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type atomic_int - #define __pyx_atomic_ptr_type atomic_uintptr_t - #define __pyx_nonatomic_ptr_type uintptr_t - #define __pyx_atomic_incr_relaxed(value) atomic_fetch_add_explicit(value, 1, memory_order_relaxed) - #define __pyx_atomic_incr_acq_rel(value) atomic_fetch_add_explicit(value, 1, memory_order_acq_rel) - #define __pyx_atomic_decr_acq_rel(value) atomic_fetch_sub_explicit(value, 1, memory_order_acq_rel) - #define __pyx_atomic_sub(value, arg) atomic_fetch_sub(value, arg) - #define __pyx_atomic_int_cmp_exchange(value, expected, desired) atomic_compare_exchange_strong(value, expected, desired) - #define __pyx_atomic_load(value) atomic_load(value) - #define __pyx_atomic_store(value, new_value) atomic_store(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) atomic_load_explicit(value, memory_order_relaxed) - #define __pyx_atomic_pointer_load_acquire(value) atomic_load_explicit(value, memory_order_acquire) - #define __pyx_atomic_pointer_exchange(value, new_value) atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) - #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) - #pragma message ("Using standard C atomics") - #elif defined(__PYX_DEBUG_ATOMICS) - #warning "Using standard C atomics" - #endif -#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ - (__cplusplus >= 201103L) ||\ -\ - (defined(_MSC_VER) && _MSC_VER >= 1700)) &&\ - ATOMIC_INT_LOCK_FREE == 2) - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type std::atomic_int - #define __pyx_atomic_ptr_type std::atomic_uintptr_t - #define __pyx_nonatomic_ptr_type uintptr_t - #define __pyx_atomic_incr_relaxed(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_relaxed) - #define __pyx_atomic_incr_acq_rel(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_acq_rel) - #define __pyx_atomic_decr_acq_rel(value) std::atomic_fetch_sub_explicit(value, 1, std::memory_order_acq_rel) - #define __pyx_atomic_sub(value, arg) std::atomic_fetch_sub(value, arg) - #define __pyx_atomic_int_cmp_exchange(value, expected, desired) std::atomic_compare_exchange_strong(value, expected, desired) - #define __pyx_atomic_load(value) std::atomic_load(value) - #define __pyx_atomic_store(value, new_value) std::atomic_store(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) std::atomic_load_explicit(value, std::memory_order_relaxed) - #define __pyx_atomic_pointer_load_acquire(value) std::atomic_load_explicit(value, std::memory_order_acquire) - #define __pyx_atomic_pointer_exchange(value, new_value) std::atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) - #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) - #pragma message ("Using standard C++ atomics") - #elif defined(__PYX_DEBUG_ATOMICS) - #warning "Using standard C++ atomics" - #endif -#elif CYTHON_ATOMICS && (__GNUC__ >= 5 || (__GNUC__ == 4 &&\ - (__GNUC_MINOR__ > 1 ||\ - (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 2)))) - #define __pyx_atomic_ptr_type void* - #define __pyx_atomic_incr_relaxed(value) __sync_fetch_and_add(value, 1) - #define __pyx_atomic_incr_acq_rel(value) __sync_fetch_and_add(value, 1) - #define __pyx_atomic_decr_acq_rel(value) __sync_fetch_and_sub(value, 1) - #define __pyx_atomic_sub(value, arg) __sync_fetch_and_sub(value, arg) - static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { - __pyx_nonatomic_int_type old = __sync_val_compare_and_swap(value, *expected, desired); - int result = old == *expected; - *expected = old; - return result; - } - #define __pyx_atomic_load(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_store(value, new_value) __sync_lock_test_and_set(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_pointer_load_acquire(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_pointer_exchange(value, new_value) __sync_lock_test_and_set(value, (__pyx_atomic_ptr_type)new_value) - #ifdef __PYX_DEBUG_ATOMICS - #warning "Using GNU atomics" - #endif -#elif CYTHON_ATOMICS && defined(_MSC_VER) - #include - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type long - #define __pyx_atomic_ptr_type void* - #undef __pyx_nonatomic_int_type - #define __pyx_nonatomic_int_type long - #pragma intrinsic (_InterlockedExchangeAdd, _InterlockedExchange, _InterlockedCompareExchange, _InterlockedCompareExchangePointer, _InterlockedExchangePointer) - #define __pyx_atomic_incr_relaxed(value) _InterlockedExchangeAdd(value, 1) - #define __pyx_atomic_incr_acq_rel(value) _InterlockedExchangeAdd(value, 1) - #define __pyx_atomic_decr_acq_rel(value) _InterlockedExchangeAdd(value, -1) - #define __pyx_atomic_sub(value, arg) _InterlockedExchangeAdd(value, -arg) - static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { - __pyx_nonatomic_int_type old = _InterlockedCompareExchange(value, desired, *expected); - int result = old == *expected; - *expected = old; - return result; - } - #define __pyx_atomic_load(value) _InterlockedExchangeAdd(value, 0) - #define __pyx_atomic_store(value, new_value) _InterlockedExchange(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) *(void * volatile *)value - #define __pyx_atomic_pointer_load_acquire(value) _InterlockedCompareExchangePointer(value, 0, 0) - #define __pyx_atomic_pointer_exchange(value, new_value) _InterlockedExchangePointer(value, (__pyx_atomic_ptr_type)new_value) - #ifdef __PYX_DEBUG_ATOMICS - #pragma message ("Using MSVC atomics") - #endif -#else - #undef CYTHON_ATOMICS - #define CYTHON_ATOMICS 0 - #ifdef __PYX_DEBUG_ATOMICS - #warning "Not using atomics" - #endif -#endif -#if CYTHON_ATOMICS - #define __pyx_add_acquisition_count(memview)\ - __pyx_atomic_incr_relaxed(__pyx_get_slice_count_pointer(memview)) - #define __pyx_sub_acquisition_count(memview)\ - __pyx_atomic_decr_acq_rel(__pyx_get_slice_count_pointer(memview)) -#else - #define __pyx_add_acquisition_count(memview)\ - __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) - #define __pyx_sub_acquisition_count(memview)\ - __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) -#endif - -/* IncludeStructmemberH.proto */ -#include - -/* CriticalSections.proto */ -#if !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING -#define __Pyx_PyCriticalSection void* -#define __Pyx_PyCriticalSection2 void* -#define __Pyx_PyCriticalSection_Begin1(cs, arg) (void)cs -#define __Pyx_PyCriticalSection_Begin2(cs, arg1, arg2) (void)cs -#define __Pyx_PyCriticalSection_End1(cs) -#define __Pyx_PyCriticalSection_End2(cs) -#else -#define __Pyx_PyCriticalSection PyCriticalSection -#define __Pyx_PyCriticalSection2 PyCriticalSection2 -#define __Pyx_PyCriticalSection_Begin1 PyCriticalSection_Begin -#define __Pyx_PyCriticalSection_Begin2 PyCriticalSection2_Begin -#define __Pyx_PyCriticalSection_End1 PyCriticalSection_End -#define __Pyx_PyCriticalSection_End2 PyCriticalSection2_End -#endif -#if PY_VERSION_HEX < 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_BEGIN_CRITICAL_SECTION(o) { -#define __Pyx_END_CRITICAL_SECTION() } -#else -#define __Pyx_BEGIN_CRITICAL_SECTION Py_BEGIN_CRITICAL_SECTION -#define __Pyx_END_CRITICAL_SECTION Py_END_CRITICAL_SECTION -#endif - -/* #### Code section: numeric_typedefs ### */ -/* #### Code section: complex_type_declarations ### */ -/* #### Code section: type_declarations ### */ - -/*--- Type declarations ---*/ -/* #### Code section: utility_code_proto ### */ - -/* --- Runtime support code (head) --- */ -/* Refnanny.proto */ -#ifndef CYTHON_REFNANNY - #define CYTHON_REFNANNY 0 -#endif -#if CYTHON_REFNANNY - typedef struct { - void (*INCREF)(void*, PyObject*, Py_ssize_t); - void (*DECREF)(void*, PyObject*, Py_ssize_t); - void (*GOTREF)(void*, PyObject*, Py_ssize_t); - void (*GIVEREF)(void*, PyObject*, Py_ssize_t); - void* (*SetupContext)(const char*, Py_ssize_t, const char*); - void (*FinishContext)(void**); - } __Pyx_RefNannyAPIStruct; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); - #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; - #define __Pyx_RefNannySetupContext(name, acquire_gil)\ - if (acquire_gil) {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ - PyGILState_Release(__pyx_gilstate_save);\ - } else {\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ - } - #define __Pyx_RefNannyFinishContextNogil() {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __Pyx_RefNannyFinishContext();\ - PyGILState_Release(__pyx_gilstate_save);\ - } - #define __Pyx_RefNannyFinishContextNogil() {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __Pyx_RefNannyFinishContext();\ - PyGILState_Release(__pyx_gilstate_save);\ - } - #define __Pyx_RefNannyFinishContext()\ - __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) - #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) - #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) - #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) -#else - #define __Pyx_RefNannyDeclarations - #define __Pyx_RefNannySetupContext(name, acquire_gil) - #define __Pyx_RefNannyFinishContextNogil() - #define __Pyx_RefNannyFinishContext() - #define __Pyx_INCREF(r) Py_INCREF(r) - #define __Pyx_DECREF(r) Py_DECREF(r) - #define __Pyx_GOTREF(r) - #define __Pyx_GIVEREF(r) - #define __Pyx_XINCREF(r) Py_XINCREF(r) - #define __Pyx_XDECREF(r) Py_XDECREF(r) - #define __Pyx_XGOTREF(r) - #define __Pyx_XGIVEREF(r) -#endif -#define __Pyx_Py_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; Py_XDECREF(tmp);\ - } while (0) -#define __Pyx_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_XDECREF(tmp);\ - } while (0) -#define __Pyx_DECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_DECREF(tmp);\ - } while (0) -#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) -#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) - -/* PyErrExceptionMatches.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) -static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); -#else -#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) -#endif - -/* PyThreadStateGet.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; -#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; -#if PY_VERSION_HEX >= 0x030C00A6 -#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) -#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) -#else -#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) -#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) -#endif -#else -#define __Pyx_PyThreadState_declare -#define __Pyx_PyThreadState_assign -#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) -#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() -#endif - -/* PyErrFetchRestore.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) -#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 -#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) -#else -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#endif -#else -#define __Pyx_PyErr_Clear() PyErr_Clear() -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) -#endif - -/* PyObjectGetAttrStr.proto */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); -#else -#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) -#endif - -/* PyObjectGetAttrStrNoError.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); - -/* GetBuiltinName.proto */ -static PyObject *__Pyx_GetBuiltinName(PyObject *name); - -/* TupleAndListFromArray.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n); -#endif -#if CYTHON_COMPILING_IN_CPYTHON || CYTHON_METH_FASTCALL -static CYTHON_INLINE PyObject* __Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n); -#endif - -/* IncludeStringH.proto */ -#include - -/* BytesEquals.proto */ -static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals); - -/* UnicodeEquals.proto */ -static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals); - -/* fastcall.proto */ -#if CYTHON_AVOID_BORROWED_REFS - #define __Pyx_ArgRef_VARARGS(args, i) __Pyx_PySequence_ITEM(args, i) -#elif CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_ArgRef_VARARGS(args, i) __Pyx_NewRef(__Pyx_PyTuple_GET_ITEM(args, i)) -#else - #define __Pyx_ArgRef_VARARGS(args, i) __Pyx_XNewRef(PyTuple_GetItem(args, i)) -#endif -#define __Pyx_NumKwargs_VARARGS(kwds) PyDict_Size(kwds) -#define __Pyx_KwValues_VARARGS(args, nargs) NULL -#define __Pyx_GetKwValue_VARARGS(kw, kwvalues, s) __Pyx_PyDict_GetItemStrWithError(kw, s) -#define __Pyx_KwargsAsDict_VARARGS(kw, kwvalues) PyDict_Copy(kw) -#if CYTHON_METH_FASTCALL - #define __Pyx_ArgRef_FASTCALL(args, i) __Pyx_NewRef(args[i]) - #define __Pyx_NumKwargs_FASTCALL(kwds) __Pyx_PyTuple_GET_SIZE(kwds) - #define __Pyx_KwValues_FASTCALL(args, nargs) ((args) + (nargs)) - static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s); - #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API - CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues); - #else - #define __Pyx_KwargsAsDict_FASTCALL(kw, kwvalues) _PyStack_AsDict(kwvalues, kw) - #endif -#else - #define __Pyx_ArgRef_FASTCALL __Pyx_ArgRef_VARARGS - #define __Pyx_NumKwargs_FASTCALL __Pyx_NumKwargs_VARARGS - #define __Pyx_KwValues_FASTCALL __Pyx_KwValues_VARARGS - #define __Pyx_GetKwValue_FASTCALL __Pyx_GetKwValue_VARARGS - #define __Pyx_KwargsAsDict_FASTCALL __Pyx_KwargsAsDict_VARARGS -#endif -#define __Pyx_ArgsSlice_VARARGS(args, start, stop) PyTuple_GetSlice(args, start, stop) -#if CYTHON_METH_FASTCALL || (CYTHON_COMPILING_IN_CPYTHON && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) -#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) __Pyx_PyTuple_FromArray(args + start, stop - start) -#else -#define __Pyx_ArgsSlice_FASTCALL(args, start, stop) PyTuple_GetSlice(args, start, stop) -#endif - -/* PyDictVersioning.proto */ -#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS -#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) -#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ - (version_var) = __PYX_GET_DICT_VERSION(dict);\ - (cache_var) = (value); -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ - static PY_UINT64_T __pyx_dict_version = 0;\ - static PyObject *__pyx_dict_cached_value = NULL;\ - if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ - (VAR) = __pyx_dict_cached_value;\ - } else {\ - (VAR) = __pyx_dict_cached_value = (LOOKUP);\ - __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ - }\ -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); -#else -#define __PYX_GET_DICT_VERSION(dict) (0) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); -#endif - -/* GetModuleGlobalName.proto */ -#if CYTHON_USE_DICT_VERSIONS -#define __Pyx_GetModuleGlobalName(var, name) do {\ - static PY_UINT64_T __pyx_dict_version = 0;\ - static PyObject *__pyx_dict_cached_value = NULL;\ - (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_mstate_global->__pyx_d))) ?\ - (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ - __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ -} while(0) -#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ - PY_UINT64_T __pyx_dict_version;\ - PyObject *__pyx_dict_cached_value;\ - (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ -} while(0) -static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); -#else -#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) -#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) -static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); -#endif - -/* PyFunctionFastCall.proto */ -#if CYTHON_FAST_PYCALL -#if !CYTHON_VECTORCALL -#define __Pyx_PyFunction_FastCall(func, args, nargs)\ - __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs); -#endif -#define __Pyx_BUILD_ASSERT_EXPR(cond)\ - (sizeof(char [1 - 2*!(cond)]) - 1) -#ifndef Py_MEMBER_SIZE -#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) -#endif -#if !CYTHON_VECTORCALL -#if PY_VERSION_HEX >= 0x03080000 - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets() - #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) -#else - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ - ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -#endif -#endif -#endif - -/* PyObjectCall.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); -#else -#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) -#endif - -/* PyObjectCallMethO.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); -#endif - -/* PyObjectFastCall.proto */ -#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) -static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs); - -/* PyObjectFormatSimple.proto */ -#if CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyObject_FormatSimple(s, f) (\ - likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ - PyObject_Format(s, f)) -#elif CYTHON_USE_TYPE_SLOTS - #define __Pyx_PyObject_FormatSimple(s, f) (\ - likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ - likely(PyLong_CheckExact(s)) ? PyLong_Type.tp_repr(s) :\ - likely(PyFloat_CheckExact(s)) ? PyFloat_Type.tp_repr(s) :\ - PyObject_Format(s, f)) -#else - #define __Pyx_PyObject_FormatSimple(s, f) (\ - likely(PyUnicode_CheckExact(s)) ? (Py_INCREF(s), s) :\ - PyObject_Format(s, f)) -#endif - -/* JoinPyUnicode.proto */ -static PyObject* __Pyx_PyUnicode_Join(PyObject** values, Py_ssize_t value_count, Py_ssize_t result_ulength, - Py_UCS4 max_char); - -/* RaiseException.proto */ -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); - -/* RaiseDoubleKeywords.proto */ -static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); - -/* ParseKeywords.proto */ -static CYTHON_INLINE int __Pyx_ParseKeywords( - PyObject *kwds, PyObject *const *kwvalues, PyObject ** const argnames[], - PyObject *kwds2, PyObject *values[], - Py_ssize_t num_pos_args, Py_ssize_t num_kwargs, - const char* function_name, - int ignore_unknown_kwargs -); - -/* CallCFunction.proto */ -#define __Pyx_CallCFunction(cfunc, self, args)\ - ((PyCFunction)(void(*)(void))(cfunc)->func)(self, args) -#define __Pyx_CallCFunctionWithKeywords(cfunc, self, args, kwargs)\ - ((PyCFunctionWithKeywords)(void(*)(void))(cfunc)->func)(self, args, kwargs) -#define __Pyx_CallCFunctionFast(cfunc, self, args, nargs)\ - ((__Pyx_PyCFunctionFast)(void(*)(void))(PyCFunction)(cfunc)->func)(self, args, nargs) -#define __Pyx_CallCFunctionFastWithKeywords(cfunc, self, args, nargs, kwnames)\ - ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))(PyCFunction)(cfunc)->func)(self, args, nargs, kwnames) - -/* UnpackUnboundCMethod.proto */ -typedef struct { - PyObject *type; - PyObject **method_name; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && CYTHON_ATOMICS - __pyx_atomic_int_type initialized; -#endif - PyCFunction func; - PyObject *method; - int flag; -} __Pyx_CachedCFunction; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING -static CYTHON_INLINE int __Pyx_CachedCFunction_GetAndSetInitializing(__Pyx_CachedCFunction *cfunc) { -#if !CYTHON_ATOMICS - return 1; -#else - __pyx_nonatomic_int_type expected = 0; - if (__pyx_atomic_int_cmp_exchange(&cfunc->initialized, &expected, 1)) { - return 0; - } - return expected; -#endif -} -static CYTHON_INLINE void __Pyx_CachedCFunction_SetFinishedInitializing(__Pyx_CachedCFunction *cfunc) { -#if CYTHON_ATOMICS - __pyx_atomic_store(&cfunc->initialized, 2); -#endif -} -#else -#define __Pyx_CachedCFunction_GetAndSetInitializing(cfunc) 2 -#define __Pyx_CachedCFunction_SetFinishedInitializing(cfunc) -#endif - -/* CallUnboundCMethod2.proto */ -CYTHON_UNUSED -static PyObject* __Pyx__CallUnboundCMethod2(__Pyx_CachedCFunction* cfunc, PyObject* self, PyObject* arg1, PyObject* arg2); -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject *__Pyx_CallUnboundCMethod2(__Pyx_CachedCFunction *cfunc, PyObject *self, PyObject *arg1, PyObject *arg2); -#else -#define __Pyx_CallUnboundCMethod2(cfunc, self, arg1, arg2) __Pyx__CallUnboundCMethod2(cfunc, self, arg1, arg2) -#endif - -/* RaiseArgTupleInvalid.proto */ -static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, - Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); - -/* ArgTypeTest.proto */ -#define __Pyx_ArgTypeTest(obj, type, none_allowed, name, exact)\ - ((likely(__Pyx_IS_TYPE(obj, type) | (none_allowed && (obj == Py_None)))) ? 1 :\ - __Pyx__ArgTypeTest(obj, type, name, exact)) -static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact); - -/* PyObjectSetAttrStr.proto */ -#if CYTHON_USE_TYPE_SLOTS -#define __Pyx_PyObject_DelAttrStr(o,n) __Pyx_PyObject_SetAttrStr(o, n, NULL) -static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value); -#else -#define __Pyx_PyObject_DelAttrStr(o,n) PyObject_DelAttr(o,n) -#define __Pyx_PyObject_SetAttrStr(o,n,v) PyObject_SetAttr(o,n,v) -#endif - -/* PyObjectFastCallMethod.proto */ -#if CYTHON_VECTORCALL && PY_VERSION_HEX >= 0x03090000 -#define __Pyx_PyObject_FastCallMethod(name, args, nargsf) PyObject_VectorcallMethod(name, args, nargsf, NULL) -#else -static PyObject *__Pyx_PyObject_FastCallMethod(PyObject *name, PyObject *const *args, size_t nargsf); -#endif - -/* PyLongCompare.proto */ -static CYTHON_INLINE int __Pyx_PyLong_BoolNeObjC(PyObject *op1, PyObject *op2, long intval, long inplace); - -/* AssertionsEnabled.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API || (CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030C0000) - static int __pyx_assertions_enabled_flag; - #define __pyx_assertions_enabled() (__pyx_assertions_enabled_flag) - static int __Pyx_init_assertions_enabled(void) { - PyObject *builtins, *debug, *debug_str; - int flag; - builtins = PyEval_GetBuiltins(); - if (!builtins) goto bad; - debug_str = PyUnicode_FromStringAndSize("__debug__", 9); - if (!debug_str) goto bad; - debug = PyObject_GetItem(builtins, debug_str); - Py_DECREF(debug_str); - if (!debug) goto bad; - flag = PyObject_IsTrue(debug); - Py_DECREF(debug); - if (flag == -1) goto bad; - __pyx_assertions_enabled_flag = flag; - return 0; - bad: - __pyx_assertions_enabled_flag = 1; - return -1; - } -#else - #define __Pyx_init_assertions_enabled() (0) - #define __pyx_assertions_enabled() (!Py_OptimizeFlag) -#endif - -/* PyObjectCallNoArg.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func); - -/* RaiseUnexpectedTypeError.proto */ -static int __Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj); - -/* PyLongCompare.proto */ -static CYTHON_INLINE int __Pyx_PyLong_BoolEqObjC(PyObject *op1, PyObject *op2, long intval, long inplace); - -/* GetItemInt.proto */ -#define __Pyx_GetItemInt(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ - (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ - __Pyx_GetItemInt_Fast(o, (Py_ssize_t)i, is_list, wraparound, boundscheck) :\ - (is_list ? (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL) :\ - __Pyx_GetItemInt_Generic(o, to_py_func(i)))) -#define __Pyx_GetItemInt_List(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ - (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ - __Pyx_GetItemInt_List_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ - (PyErr_SetString(PyExc_IndexError, "list index out of range"), (PyObject*)NULL)) -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, - int wraparound, int boundscheck); -#define __Pyx_GetItemInt_Tuple(o, i, type, is_signed, to_py_func, is_list, wraparound, boundscheck)\ - (__Pyx_fits_Py_ssize_t(i, type, is_signed) ?\ - __Pyx_GetItemInt_Tuple_Fast(o, (Py_ssize_t)i, wraparound, boundscheck) :\ - (PyErr_SetString(PyExc_IndexError, "tuple index out of range"), (PyObject*)NULL)) -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, - int wraparound, int boundscheck); -static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j); -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, - int is_list, int wraparound, int boundscheck); - -/* PyObjectCallOneArg.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg); - -/* ObjectGetItem.proto */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key); -#else -#define __Pyx_PyObject_GetItem(obj, key) PyObject_GetItem(obj, key) -#endif - -/* ListAppend.proto */ -#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS -static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { - PyListObject* L = (PyListObject*) list; - Py_ssize_t len = Py_SIZE(list); - if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { - Py_INCREF(x); - #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 - L->ob_item[len] = x; - #else - PyList_SET_ITEM(list, len, x); - #endif - __Pyx_SET_SIZE(list, len + 1); - return 0; - } - return PyList_Append(list, x); -} -#else -#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) -#endif - -/* PyLongBinop.proto */ -#if !CYTHON_COMPILING_IN_PYPY -static CYTHON_INLINE PyObject* __Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check); -#else -#define __Pyx_PyLong_AddObjC(op1, op2, intval, inplace, zerodivision_check)\ - (inplace ? PyNumber_InPlaceAdd(op1, op2) : PyNumber_Add(op1, op2)) -#endif - -/* DictGetItem.proto */ -#if !CYTHON_COMPILING_IN_PYPY -static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key); -#define __Pyx_PyObject_Dict_GetItem(obj, name)\ - (likely(PyDict_CheckExact(obj)) ?\ - __Pyx_PyDict_GetItem(obj, name) : PyObject_GetItem(obj, name)) -#else -#define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key) -#define __Pyx_PyObject_Dict_GetItem(obj, name) PyObject_GetItem(obj, name) -#endif - -/* PyLongBinop.proto */ -#if !CYTHON_COMPILING_IN_PYPY -static CYTHON_INLINE PyObject* __Pyx_PyLong_SubtractObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check); -#else -#define __Pyx_PyLong_SubtractObjC(op1, op2, intval, inplace, zerodivision_check)\ - (inplace ? PyNumber_InPlaceSubtract(op1, op2) : PyNumber_Subtract(op1, op2)) -#endif - -/* PyObjectCall2Args.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2); - -/* PyObjectGetMethod.proto */ -static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method); - -/* PyObjectCallMethod1.proto */ -static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg); - -/* append.proto */ -static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x); - -/* PyFloatBinop.proto */ -#if !CYTHON_COMPILING_IN_PYPY -static int __Pyx_PyFloat_BoolEqObjC(PyObject *op1, PyObject *op2, double floatval, int inplace, int zerodivision_check); -#else -#define __Pyx_PyFloat_BoolEqObjC(op1, op2, floatval, inplace, zerodivision_check)\ - __Pyx_PyObject_IsTrueAndDecref(PyObject_RichCompare(op1, op2, Py_EQ)) - #endif - -/* PyObjectLookupSpecial.proto */ -#if CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS -#define __Pyx_PyObject_LookupSpecialNoError(obj, attr_name) __Pyx__PyObject_LookupSpecial(obj, attr_name, 0) -#define __Pyx_PyObject_LookupSpecial(obj, attr_name) __Pyx__PyObject_LookupSpecial(obj, attr_name, 1) -static CYTHON_INLINE PyObject* __Pyx__PyObject_LookupSpecial(PyObject* obj, PyObject* attr_name, int with_error); -#else -#define __Pyx_PyObject_LookupSpecialNoError(o,n) __Pyx_PyObject_GetAttrStrNoError(o,n) -#define __Pyx_PyObject_LookupSpecial(o,n) __Pyx_PyObject_GetAttrStr(o,n) -#endif - -/* GetTopmostException.proto */ -#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE -static _PyErr_StackItem * __Pyx_PyErr_GetTopmostException(PyThreadState *tstate); -#endif - -/* SaveResetException.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_ExceptionSave(type, value, tb) __Pyx__ExceptionSave(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#define __Pyx_ExceptionReset(type, value, tb) __Pyx__ExceptionReset(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); -#else -#define __Pyx_ExceptionSave(type, value, tb) PyErr_GetExcInfo(type, value, tb) -#define __Pyx_ExceptionReset(type, value, tb) PyErr_SetExcInfo(type, value, tb) -#endif - -/* GetException.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_GetException(type, value, tb) __Pyx__GetException(__pyx_tstate, type, value, tb) -static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#else -static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); -#endif - -/* Import.proto */ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level); - -/* ImportDottedModule.proto */ -static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple); -static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple); - -/* ListPack.proto */ -static PyObject *__Pyx_PyList_Pack(Py_ssize_t n, ...); - -/* ImportFrom.proto */ -static PyObject* __Pyx_ImportFrom(PyObject* module, PyObject* name); - -/* FixUpExtensionType.proto */ -static CYTHON_INLINE int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type); - -/* FetchSharedCythonModule.proto */ -static PyObject *__Pyx_FetchSharedCythonABIModule(void); - -/* dict_setdefault.proto */ -static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, int is_safe_type); - -/* FetchCommonType.proto */ -static PyTypeObject* __Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases); - -/* CallTypeTraverse.proto */ -#if !CYTHON_USE_TYPE_SPECS || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x03090000) -#define __Pyx_call_type_traverse(o, always_call, visit, arg) 0 -#else -static int __Pyx_call_type_traverse(PyObject *o, int always_call, visitproc visit, void *arg); -#endif - -/* PyMethodNew.proto */ -static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ); - -/* PyVectorcallFastCallDict.proto */ -#if CYTHON_METH_FASTCALL && (CYTHON_VECTORCALL || CYTHON_BACKPORT_VECTORCALL) -static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw); -#endif - -/* CythonFunctionShared.proto */ -#define __Pyx_CyFunction_USED -#define __Pyx_CYFUNCTION_STATICMETHOD 0x01 -#define __Pyx_CYFUNCTION_CLASSMETHOD 0x02 -#define __Pyx_CYFUNCTION_CCLASS 0x04 -#define __Pyx_CYFUNCTION_COROUTINE 0x08 -#define __Pyx_CyFunction_GetClosure(f)\ - (((__pyx_CyFunctionObject *) (f))->func_closure) -#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_CyFunction_GetClassObj(f)\ - (((__pyx_CyFunctionObject *) (f))->func_classobj) -#else - #define __Pyx_CyFunction_GetClassObj(f)\ - ((PyObject*) ((PyCMethodObject *) (f))->mm_class) -#endif -#define __Pyx_CyFunction_SetClassObj(f, classobj)\ - __Pyx__CyFunction_SetClassObj((__pyx_CyFunctionObject *) (f), (classobj)) -#define __Pyx_CyFunction_Defaults(type, f)\ - ((type *)(((__pyx_CyFunctionObject *) (f))->defaults)) -#define __Pyx_CyFunction_SetDefaultsGetter(f, g)\ - ((__pyx_CyFunctionObject *) (f))->defaults_getter = (g) -typedef struct { -#if CYTHON_COMPILING_IN_LIMITED_API - PyObject_HEAD - PyObject *func; -#elif PY_VERSION_HEX < 0x030900B1 - PyCFunctionObject func; -#else - PyCMethodObject func; -#endif -#if CYTHON_BACKPORT_VECTORCALL ||\ - (CYTHON_COMPILING_IN_LIMITED_API && CYTHON_METH_FASTCALL) - __pyx_vectorcallfunc func_vectorcall; -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - PyObject *func_weakreflist; -#endif - PyObject *func_dict; - PyObject *func_name; - PyObject *func_qualname; - PyObject *func_doc; - PyObject *func_globals; - PyObject *func_code; - PyObject *func_closure; -#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API - PyObject *func_classobj; -#endif - PyObject *defaults; - int flags; - PyObject *defaults_tuple; - PyObject *defaults_kwdict; - PyObject *(*defaults_getter)(PyObject *); - PyObject *func_annotations; - PyObject *func_is_coroutine; -} __pyx_CyFunctionObject; -#undef __Pyx_CyOrPyCFunction_Check -#define __Pyx_CyFunction_Check(obj) __Pyx_TypeCheck(obj, __pyx_mstate_global->__pyx_CyFunctionType) -#define __Pyx_CyOrPyCFunction_Check(obj) __Pyx_TypeCheck2(obj, __pyx_mstate_global->__pyx_CyFunctionType, &PyCFunction_Type) -#define __Pyx_CyFunction_CheckExact(obj) __Pyx_IS_TYPE(obj, __pyx_mstate_global->__pyx_CyFunctionType) -static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void (*cfunc)(void)); -#undef __Pyx_IsSameCFunction -#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCyOrCFunction(func, cfunc) -static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject* op, PyMethodDef *ml, - int flags, PyObject* qualname, - PyObject *closure, - PyObject *module, PyObject *globals, - PyObject* code); -static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj); -static CYTHON_INLINE PyObject *__Pyx_CyFunction_InitDefaults(PyObject *func, - PyTypeObject *defaults_type); -static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *m, - PyObject *tuple); -static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *m, - PyObject *dict); -static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *m, - PyObject *dict); -static int __pyx_CyFunction_init(PyObject *module); -#if CYTHON_METH_FASTCALL -static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); -static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); -static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); -static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames); -#if CYTHON_BACKPORT_VECTORCALL || CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_CyFunction_func_vectorcall(f) (((__pyx_CyFunctionObject*)f)->func_vectorcall) -#else -#define __Pyx_CyFunction_func_vectorcall(f) (((PyCFunctionObject*)f)->vectorcall) -#endif -#endif - -/* CythonFunction.proto */ -static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, - int flags, PyObject* qualname, - PyObject *closure, - PyObject *module, PyObject *globals, - PyObject* code); - -/* SetNameInClass.proto */ -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030d0000 -#define __Pyx_SetNameInClass(ns, name, value)\ - (likely(PyDict_CheckExact(ns)) ? _PyDict_SetItem_KnownHash(ns, name, value, ((PyASCIIObject *) name)->hash) : PyObject_SetItem(ns, name, value)) -#elif CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_SetNameInClass(ns, name, value)\ - (likely(PyDict_CheckExact(ns)) ? PyDict_SetItem(ns, name, value) : PyObject_SetItem(ns, name, value)) -#else -#define __Pyx_SetNameInClass(ns, name, value) PyObject_SetItem(ns, name, value) -#endif - -/* CalculateMetaclass.proto */ -static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases); - -/* Py3ClassCreate.proto */ -static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *qualname, - PyObject *mkw, PyObject *modname, PyObject *doc); -static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, - PyObject *mkw, int calculate_metaclass, int allow_py2_metaclass); - -/* CLineInTraceback.proto */ -#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME -static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); -#else -#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) -#endif - -/* CodeObjectCache.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API -typedef PyObject __Pyx_CachedCodeObjectType; -#else -typedef PyCodeObject __Pyx_CachedCodeObjectType; -#endif -typedef struct { - __Pyx_CachedCodeObjectType* code_object; - int code_line; -} __Pyx_CodeObjectCacheEntry; -struct __Pyx_CodeObjectCache { - int count; - int max_count; - __Pyx_CodeObjectCacheEntry* entries; - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_int_type accessor_count; - #endif -}; -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); -static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line); -static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object); - -/* AddTraceback.proto */ -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - -/* GCCDiagnostics.proto */ -#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define __Pyx_HAS_GCC_DIAGNOSTIC -#endif - -/* CIntFromPy.proto */ -static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *); - -/* PyObjectVectorCallKwBuilder.proto */ -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); -#if CYTHON_VECTORCALL -#if PY_VERSION_HEX >= 0x03090000 -#define __Pyx_Object_Vectorcall_CallFromBuilder PyObject_Vectorcall -#else -#define __Pyx_Object_Vectorcall_CallFromBuilder _PyObject_Vectorcall -#endif -#define __Pyx_MakeVectorcallBuilderKwds(n) PyTuple_New(n) -static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); -static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n); -#else -#define __Pyx_Object_Vectorcall_CallFromBuilder __Pyx_PyObject_FastCallDict -#define __Pyx_MakeVectorcallBuilderKwds(n) __Pyx_PyDict_NewPresized(n) -#define __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n) PyDict_SetItem(builder, key, value) -#define __Pyx_VectorcallBuilder_AddArgStr(key, value, builder, args, n) PyDict_SetItemString(builder, key, value) -#endif - -/* CIntToPy.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value); - -/* FormatTypeName.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API -typedef PyObject *__Pyx_TypeName; -#define __Pyx_FMT_TYPENAME "%U" -#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 -#define __Pyx_PyType_GetFullyQualifiedName PyType_GetFullyQualifiedName -#else -static __Pyx_TypeName __Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp); -#endif -#else // !LIMITED_API -typedef const char *__Pyx_TypeName; -#define __Pyx_FMT_TYPENAME "%.200s" -#define __Pyx_PyType_GetFullyQualifiedName(tp) ((tp)->tp_name) -#define __Pyx_DECREF_TypeName(obj) -#endif - -/* CIntFromPy.proto */ -static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *); - -/* FastTypeChecks.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); -static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); -#else -#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) -#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) -#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2) { - return PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2); -} -#endif -#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) -#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) -#ifdef PyExceptionInstance_Check - #define __Pyx_PyBaseException_Check(obj) PyExceptionInstance_Check(obj) -#else - #define __Pyx_PyBaseException_Check(obj) __Pyx_TypeCheck(obj, PyExc_BaseException) -#endif - -/* GetRuntimeVersion.proto */ -static unsigned long __Pyx_get_runtime_version(void); - -/* CheckBinaryVersion.proto */ -static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); - -/* MultiPhaseInitModuleState.proto */ -#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE -static PyObject *__Pyx_State_FindModule(void*); -static int __Pyx_State_AddModule(PyObject* module, void*); -static int __Pyx_State_RemoveModule(void*); -#elif CYTHON_USE_MODULE_STATE -#define __Pyx_State_FindModule PyState_FindModule -#define __Pyx_State_AddModule PyState_AddModule -#define __Pyx_State_RemoveModule PyState_RemoveModule -#endif - -/* #### Code section: module_declarations ### */ -/* CythonABIVersion.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API - #if CYTHON_METH_FASTCALL - #define __PYX_FASTCALL_ABI_SUFFIX "_fastcall" - #else - #define __PYX_FASTCALL_ABI_SUFFIX - #endif - #define __PYX_LIMITED_ABI_SUFFIX "limited" __PYX_FASTCALL_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX -#else - #define __PYX_LIMITED_ABI_SUFFIX -#endif -#if __PYX_HAS_PY_AM_SEND == 1 - #define __PYX_AM_SEND_ABI_SUFFIX -#elif __PYX_HAS_PY_AM_SEND == 2 - #define __PYX_AM_SEND_ABI_SUFFIX "amsendbackport" -#else - #define __PYX_AM_SEND_ABI_SUFFIX "noamsend" -#endif -#ifndef __PYX_MONITORING_ABI_SUFFIX - #define __PYX_MONITORING_ABI_SUFFIX -#endif -#if CYTHON_USE_TP_FINALIZE - #define __PYX_TP_FINALIZE_ABI_SUFFIX -#else - #define __PYX_TP_FINALIZE_ABI_SUFFIX "nofinalize" -#endif -#if CYTHON_USE_FREELISTS || !defined(__Pyx_AsyncGen_USED) - #define __PYX_FREELISTS_ABI_SUFFIX -#else - #define __PYX_FREELISTS_ABI_SUFFIX "nofreelists" -#endif -#define CYTHON_ABI __PYX_ABI_VERSION __PYX_LIMITED_ABI_SUFFIX __PYX_MONITORING_ABI_SUFFIX __PYX_TP_FINALIZE_ABI_SUFFIX __PYX_FREELISTS_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX -#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI -#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." - - -/* Module declarations from "epanet.epanet" */ -/* #### Code section: typeinfo ### */ -/* #### Code section: before_global_var ### */ -#define __Pyx_MODULE_NAME "epanet.epanet" -extern int __pyx_module_is_main_epanet__epanet; -int __pyx_module_is_main_epanet__epanet = 0; - -/* Implementation of "epanet.epanet" */ -/* #### Code section: global_var ### */ -static PyObject *__pyx_builtin_AssertionError; -static PyObject *__pyx_builtin_range; -static PyObject *__pyx_builtin_open; -/* #### Code section: string_decls ### */ -static const char __pyx_k_[] = "]"; -static const char __pyx_k_2[] = "2"; -static const char __pyx_k_d[] = "d"; -static const char __pyx_k_f[] = "f"; -static const char __pyx_k_i[] = "i"; -static const char __pyx_k_j[] = "j"; -static const char __pyx_k_k[] = "k"; -static const char __pyx_k_p[] = "p"; -static const char __pyx_k_q[] = "q"; -static const char __pyx_k_r[] = "r"; -static const char __pyx_k_t[] = "t"; -static const char __pyx_k_v[] = "v"; -static const char __pyx_k_w[] = "w"; -static const char __pyx_k__2[] = " "; -static const char __pyx_k__3[] = "."; -static const char __pyx_k__4[] = ".."; -static const char __pyx_k__5[] = "?"; -static const char __pyx_k_db[] = ".db"; -static const char __pyx_k_ds[] = "ds"; -static const char __pyx_k_os[] = "os"; -static const char __pyx_k_rb[] = "rb"; -static const char __pyx_k_ts[] = "ts"; -static const char __pyx_k_AFD[] = "AFD"; -static const char __pyx_k_Any[] = "Any"; -static const char __pyx_k_CFS[] = "CFS"; -static const char __pyx_k_CMD[] = "CMD"; -static const char __pyx_k_CMH[] = "CMH"; -static const char __pyx_k_GPM[] = "GPM"; -static const char __pyx_k_KPA[] = "KPA"; -static const char __pyx_k_LPM[] = "LPM"; -static const char __pyx_k_LPS[] = "LPS"; -static const char __pyx_k_MGD[] = "MGD"; -static const char __pyx_k_MGL[] = "MGL"; -static const char __pyx_k_MLD[] = "MLD"; -static const char __pyx_k_MTR[] = "MTR"; -static const char __pyx_k_PSI[] = "PSI"; -static const char __pyx_k_UGL[] = "UGL"; -static const char __pyx_k_api[] = "api"; -static const char __pyx_k_del[] = "__del__"; -static const char __pyx_k_dir[] = "dir"; -static const char __pyx_k_doc[] = "__doc__"; -static const char __pyx_k_exe[] = "exe"; -static const char __pyx_k_f_u[] = "f_u"; -static const char __pyx_k_inp[] = ".inp"; -static const char __pyx_k_int[] = "int"; -static const char __pyx_k_lib[] = "_lib"; -static const char __pyx_k_msg[] = "msg"; -static const char __pyx_k_opt[] = ".opt"; -static const char __pyx_k_p_u[] = "p_u"; -static const char __pyx_k_pop[] = "pop"; -static const char __pyx_k_q_u[] = "q_u"; -static const char __pyx_k_rpt[] = ".rpt"; -static const char __pyx_k_str[] = "str"; -static const char __pyx_k_sys[] = "sys"; -static const char __pyx_k_CDLL[] = "CDLL"; -static const char __pyx_k_IMGD[] = "IMGD"; -static const char __pyx_k_NONE[] = "NONE"; -static const char __pyx_k_None[] = "None"; -static const char __pyx_k_OPEN[] = "OPEN"; -static const char __pyx_k_bool[] = "bool"; -static const char __pyx_k_bulk[] = "bulk"; -static const char __pyx_k_code[] = "code"; -static const char __pyx_k_data[] = "data"; -static const char __pyx_k_dump[] = "dump"; -static const char __pyx_k_exit[] = "__exit__"; -static const char __pyx_k_f_us[] = "f_us"; -static const char __pyx_k_flow[] = "flow"; -static const char __pyx_k_func[] = "__func__"; -static const char __pyx_k_head[] = "head"; -static const char __pyx_k_init[] = "__init__"; -static const char __pyx_k_join[] = "join"; -static const char __pyx_k_json[] = ".json"; -static const char __pyx_k_link[] = "link"; -static const char __pyx_k_main[] = "__main__"; -static const char __pyx_k_name[] = "name"; -static const char __pyx_k_node[] = "node"; -static const char __pyx_k_open[] = "open"; -static const char __pyx_k_p_us[] = "p_us"; -static const char __pyx_k_path[] = "path"; -static const char __pyx_k_pump[] = "pump"; -static const char __pyx_k_q_us[] = "q_us"; -static const char __pyx_k_read[] = "read"; -static const char __pyx_k_self[] = "self"; -static const char __pyx_k_size[] = "size"; -static const char __pyx_k_spec[] = "__spec__"; -static const char __pyx_k_tank[] = "tank"; -static const char __pyx_k_temp[] = "temp"; -static const char __pyx_k_test[] = "__test__"; -static const char __pyx_k_wall[] = "wall"; -static const char __pyx_k_HOURS[] = "HOURS"; -static const char __pyx_k_PRCNT[] = "PRCNT"; -static const char __pyx_k_byref[] = "byref"; -static const char __pyx_k_c_int[] = "c_int"; -static const char __pyx_k_check[] = "_check"; -static const char __pyx_k_dumps[] = "dumps"; -static const char __pyx_k_enter[] = "__enter__"; -static const char __pyx_k_error[] = "error"; -static const char __pyx_k_index[] = "index"; -static const char __pyx_k_inp_2[] = "inp"; -static const char __pyx_k_input[] = "input"; -static const char __pyx_k_links[] = "links"; -static const char __pyx_k_nodes[] = "nodes"; -static const char __pyx_k_opt_2[] = "opt"; -static const char __pyx_k_range[] = "range"; -static const char __pyx_k_rpt_2[] = "rpt"; -static const char __pyx_k_sizes[] = "sizes"; -static const char __pyx_k_times[] = "times"; -static const char __pyx_k_units[] = "units"; -static const char __pyx_k_utf_8[] = "utf-8"; -static const char __pyx_k_value[] = "value"; -static const char __pyx_k_valve[] = "valve"; -static const char __pyx_k_CLOSED[] = "CLOSED"; -static const char __pyx_k_Output[] = "Output"; -static const char __pyx_k_append[] = "append"; -static const char __pyx_k_base64[] = "base64"; -static const char __pyx_k_ctypes[] = "ctypes"; -static const char __pyx_k_db_inp[] = "db_inp"; -static const char __pyx_k_decode[] = "decode"; -static const char __pyx_k_demand[] = "demand"; -static const char __pyx_k_encode[] = "encode"; -static const char __pyx_k_epanet[] = "epanet"; -static const char __pyx_k_failed[] = "failed"; -static const char __pyx_k_getcwd[] = "getcwd"; -static const char __pyx_k_handle[] = "_handle"; -static const char __pyx_k_json_2[] = "json"; -static const char __pyx_k_length[] = "length"; -static const char __pyx_k_module[] = "__module__"; -static const char __pyx_k_name_2[] = "__name__"; -static const char __pyx_k_output[] = "output"; -static const char __pyx_k_path_2[] = "_path"; -static const char __pyx_k_report[] = "report"; -static const char __pyx_k_result[] = "result"; -static const char __pyx_k_return[] = "return"; -static const char __pyx_k_source[] = "source"; -static const char __pyx_k_status[] = "status"; -static const char __pyx_k_system[] = "system"; -static const char __pyx_k_typing[] = "typing"; -static const char __pyx_k_usages[] = "usages"; -static const char __pyx_k_values[] = "values"; -static const char __pyx_k_POINTER[] = "POINTER"; -static const char __pyx_k_Windows[] = "Windows"; -static const char __pyx_k_abspath[] = "abspath"; -static const char __pyx_k_c_float[] = "c_float"; -static const char __pyx_k_command[] = "command"; -static const char __pyx_k_inp_out[] = "inp_out"; -static const char __pyx_k_prepare[] = "__prepare__"; -static const char __pyx_k_project[] = "project"; -static const char __pyx_k_quality[] = "quality"; -static const char __pyx_k_run_inp[] = "run_inp"; -static const char __pyx_k_setting[] = "setting"; -static const char __pyx_k_version[] = "version"; -static const char __pyx_k_ENR_free[] = "ENR_free"; -static const char __pyx_k_ENR_init[] = "ENR_init"; -static const char __pyx_k_ENR_open[] = "ENR_open"; -static const char __pyx_k_Platform[] = "Platform "; -static const char __pyx_k_add_note[] = "add_note"; -static const char __pyx_k_c_char_p[] = "c_char_p"; -static const char __pyx_k_c_void_p[] = "c_void_p"; -static const char __pyx_k_category[] = "category"; -static const char __pyx_k_cost_day[] = "cost/day"; -static const char __pyx_k_db_inp_2[] = ".db.inp"; -static const char __pyx_k_dump_inp[] = "dump_inp"; -static const char __pyx_k_friction[] = "friction"; -static const char __pyx_k_headloss[] = "headloss"; -static const char __pyx_k_name_len[] = "name_len"; -static const char __pyx_k_net_size[] = "net_size"; -static const char __pyx_k_platform[] = "platform"; -static const char __pyx_k_pressure[] = "pressure"; -static const char __pyx_k_qualname[] = "__qualname__"; -static const char __pyx_k_reaction[] = "reaction"; -static const char __pyx_k_velocity[] = "velocity"; -static const char __pyx_k_ENR_close[] = "ENR_close"; -static const char __pyx_k_b64encode[] = "b64encode"; -static const char __pyx_k_ha_4q_d_q[] = "\320\000\026\220h\230a\330\004\013\2104\210q\220\006\220d\230%\230q"; -static const char __pyx_k_ha_q_4vQa[] = "\320\000\026\220h\230a\330\004\013\210<\220q\230\001\330\004\013\2104\210v\220Q\220a"; -static const char __pyx_k_link_type[] = "link_type"; -static const char __pyx_k_metaclass[] = "__metaclass__"; -static const char __pyx_k_node_type[] = "node_type"; -static const char __pyx_k_reactions[] = "reactions"; -static const char __pyx_k_attributes[] = "attributes"; -static const char __pyx_k_avg_kwatts[] = "avg.kwatts"; -static const char __pyx_k_max_kwatts[] = "max.kwatts"; -static const char __pyx_k_platform_2[] = "_platform"; -static const char __pyx_k_q_z_A_iq_q[] = "\200\001\330\004\020\220\010\230\007\230q\330\004\007\200z\220\023\220A\330\010\016\210i\220q\230\002\230-\240q"; -static const char __pyx_k_successful[] = "successful"; -static const char __pyx_k_Output_dump[] = "Output.dump"; -static const char __pyx_k_avg_kW_flow[] = "avg.kW/flow"; -static const char __pyx_k_bast64_data[] = "bast64_data"; -static const char __pyx_k_dump_output[] = "_dump_output"; -static const char __pyx_k_dump_report[] = "dump_report"; -static const char __pyx_k_num_periods[] = "num_periods"; -static const char __pyx_k_report_step[] = "report_step"; -static const char __pyx_k_run_project[] = "run_project"; -static const char __pyx_k_utilization[] = "utilization"; -static const char __pyx_k_A_G1D_Zq_fAT[] = "\200A\340\010\014\210G\2201\220D\230\005\230Z\240q\250\006\250f\260A\260T\270\021"; -static const char __pyx_k_ENR_getTimes[] = "ENR_getTimes"; -static const char __pyx_k_ENR_getUnits[] = "ENR_getUnits"; -static const char __pyx_k_Output___del[] = "Output.__del__"; -static const char __pyx_k_Output_times[] = "Output.times"; -static const char __pyx_k_Output_units[] = "Output.units"; -static const char __pyx_k_dict_str_Any[] = "dict[str, Any]"; -static const char __pyx_k_dict_str_int[] = "dict[str, int]"; -static const char __pyx_k_dict_str_str[] = "dict[str, str]"; -static const char __pyx_k_element_name[] = "element_name"; -static const char __pyx_k_energy_usage[] = "energy_usage"; -static const char __pyx_k_have_project[] = "have_project"; -static const char __pyx_k_initializing[] = "_initializing"; -static const char __pyx_k_is_coroutine[] = "_is_coroutine"; -static const char __pyx_k_link_results[] = "link_results"; -static const char __pyx_k_node_results[] = "node_results"; -static const char __pyx_k_report_start[] = "report_start"; -static const char __pyx_k_sim_duration[] = "sim_duration"; -static const char __pyx_k_Output___init[] = "Output.__init__"; -static const char __pyx_k_Output__check[] = "Output._check"; -static const char __pyx_k_class_getitem[] = "__class_getitem__"; -static const char __pyx_k_dump_output_2[] = "dump_output"; -static const char __pyx_k_element_count[] = "element_count"; -static const char __pyx_k_epanet_epanet[] = "epanet.epanet"; -static const char __pyx_k_runepanet_exe[] = "runepanet.exe"; -static const char __pyx_k_AssertionError[] = "AssertionError"; -static const char __pyx_k_ENR_checkError[] = "ENR_checkError"; -static const char __pyx_k_ENR_getNetSize[] = "ENR_getNetSize"; -static const char __pyx_k_ENR_getVersion[] = "ENR_getVersion"; -static const char __pyx_k_Output_version[] = "Output.version"; -static const char __pyx_k_avg_efficiency[] = "avg.efficiency"; -static const char __pyx_k_dict_str_float[] = "dict[str, float]"; -static const char __pyx_k_output_message[] = "] output, message ["; -static const char __pyx_k_F_G1D__AT_6_q_q[] = "\320\004\031\230\021\330\010\014\210F\220&\230\001\330\010\014\210G\2201\220D\230\005\230_\250A\250T\260\032\2706\300\026\300q\310\001\330\010\017\210q\220\001"; -static const char __pyx_k_Output_net_size[] = "Output.net_size"; -static const char __pyx_k_readable_output[] = "readable_output"; -static const char __pyx_k_verify_platform[] = "_verify_platform"; -static const char __pyx_k_ENR_getNetReacts[] = "ENR_getNetReacts"; -static const char __pyx_k_Output_reactions[] = "Output.reactions"; -static const char __pyx_k_epanet_epanet_py[] = "epanet/epanet.py"; -static const char __pyx_k_ENR_getLinkResult[] = "ENR_getLinkResult"; -static const char __pyx_k_ENR_getNodeResult[] = "ENR_getNodeResult"; -static const char __pyx_k_Not_found_project[] = "Not found project ["; -static const char __pyx_k_dict_str_list_str[] = "dict[str, list[str]]"; -static const char __pyx_k_epanet_output_dll[] = "epanet-output.dll"; -static const char __pyx_k_list_dict_str_Any[] = "list[dict[str, Any]]"; -static const char __pyx_k_simulation_result[] = "simulation_result"; -static const char __pyx_k_xq_3e1_Qe2Yha_E_1[] = "\320\000\027\220x\230q\330\004\n\210&\220\001\220\021\330\004\013\2103\210e\2201\330\t\r\210Q\210e\2202\220Y\230h\240a\330\010\014\210E\220\021\220&\230\001\330\004\013\2101"; -static const char __pyx_k_ENR_getElementName[] = "ENR_getElementName"; -static const char __pyx_k_ENR_getEnergyUsage[] = "ENR_getEnergyUsage"; -static const char __pyx_k_XQ_QfIQ_q_Q_fJaq_s[] = "\320\000\035\230X\240Q\330\t\r\210Q\210f\220I\230Q\330\010\017\210q\220\005\220Q\330\010\026\220f\230J\240a\240q\330\010\017\210s\220!\220=\240\001"; -static const char __pyx_k_asyncio_coroutines[] = "asyncio.coroutines"; -static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; -static const char __pyx_k_dump_output_binary[] = "dump_output_binary"; -static const char __pyx_k_Output_element_name[] = "Output.element_name"; -static const char __pyx_k_Output_energy_usage[] = "Output.energy_usage"; -static const char __pyx_k_Output_link_results[] = "Output.link_results"; -static const char __pyx_k_Output_node_results[] = "Output.node_results"; -static const char __pyx_k_unsupported_not_yet[] = " unsupported (not yet)"; -static const char __pyx_k_Failed_to_read_project[] = "Failed to read project ["; -static const char __pyx_k_run_project_return_dict[] = "run_project_return_dict"; -static const char __pyx_k_a_q_d_t9A_D_a_D_a_4_A_4_A_Ja_4[] = "\320\004\026\220a\330\010\017\210q\330\010\022\220,\230d\240(\250!\330\010\022\220-\230t\2409\250A\330\010\022\220*\230D\240\006\240a\330\010\022\220*\230D\240\006\240a\330\010\022\320\022#\2404\240}\260A\330\010\022\320\022#\2404\240}\260A\330\010\022\220.\240\004\240J\250a\330\010\022\320\022#\2404\240}\260A\330\010\022\320\022#\2404\240}\260A\330\010\017\210q"; -static const char __pyx_k_a_t9Baq_d_1_M_1A_1Jhl_Q_E_as_r[] = "\320\004\036\230a\330\010\017\210t\2209\230B\230a\230q\330\010\026\220d\230&\240\002\240!\2401\330\010\020\220\004\220M\240\022\2401\240A\330\010\023\2201\220J\230h\240l\260!\330\010\r\210Q\330\010\014\210E\220\025\220a\220s\230%\230r\240\021\330\014\022\220)\2305\240\001\240\022\2402\240T\250\033\260A\330\014\020\220\005\220U\230!\2301\330\020\031\230\026\230x\240q\250\006\250i\260q\330\020\031\230\026\230v\240Q\330\020\024\220G\2301\230D\240\005\320%7\260q\270\004\270J\300c\310\023\310F\320RX\320XY\320Yb\320bh\320hn\320no\320op\330\020\027\220v\230W\240C\240s\250!\2501\330\020\035\230Q\330\020\024\220E\230\025\230a\230v\240Q\330\024\036\230a\230x\240q\250\006\250f\260A\260Q\330\020\021\220\021\220)\2307\240!\2401\330\020\024\220E\230\031\240!\2406\250\026\250q\260\001\330\014\016\210g\220Q\220a\330\010\017\210q"; -static const char __pyx_k_1_xq_iq_vQ_G1D_at_V6_SYY___a_vW[] = "\320\004\033\2301\330\010\021\220\026\220x\230q\240\006\240i\250q\330\010\021\220\026\220v\230Q\330\010\014\210G\2201\220D\230\005\320\035.\250a\250t\260:\270V\3006\310\021\310)\320SY\320Y_\320_`\320`a\330\010\017\210v\220W\230C\230q\330\010\023\2201\220H\230H\240H\250A\330\010\014\210A\330\010\014\210E\220\025\220a\220q\330\014\r\210Q\210h\220a\220v\230V\2401\240A\330\010\014\210E\220\031\230!\2306\240\026\240q\250\001\330\010\017\210q"; -static const char __pyx_k_88I_t7_q_iq_1_E_G1_RuE_E_auKuBa[] = "\320\000\"\240%\320'8\3208I\310\021\330\004\007\200t\2107\220-\230q\240\001\330\010\016\210i\220q\230\002\320\0321\260\021\340\004\n\210\"\210E\220\030\230\021\230\"\230G\2401\340\004\r\210R\210u\220E\230\021\230\"\230E\240\025\240a\240u\250K\260u\270B\270a\330\004\013\2109\220A\220V\2308\2401\340\004\014\210E\220\022\2201\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\033\260A\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\033\260F\270\"\270A\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\031\260&\270\002\270!\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\031\260&\270\002\270!\330\004\016\210b\220\004\220F\230&\240\006\240a\340\004\013\2101\340\004\r\210R\210w\220a\220q\330\004\007\200w\210c\220\021\330\010\014\210A\320\r$\240A\340\010\014\210A\320\r$\240A\330\010\013\2101\330\014\021\220\021\220,\230l\250!\2501\340\014\020\220\001\220\034\320\035/\250q\260\001\340\004\010\210\001\210\034\220[\240\001\240\021\340\004\013\2101"; -static const char __pyx_k_E_G1_E_ar_e1E_A_E_ar_e1E_b_E_ar[] = "\320\000\022\220(\230!\330\004\n\210\"\210E\220\030\230\021\230\"\230G\2401\340\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\033\260A\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\030\260\025\260b\270\001\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\031\260%\260r\270\021\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\031\260%\260r\270\021\330\004\016\210b\220\004\220F\230&\240\006\240a\340\004\013\2101\340\004\r\210R\210w\220a\220q\330\004\007\200w\210c\220\021\330\010\014\210A\320\r$\240A\340\010\014\210A\320\r$\240A\340\010\014\210A\210\\\320\031+\2501\250A\340\004\010\210\001\210\034\220[\240\001\240\021\340\004\013\2104\210v\220Q\220a"; -static const char __pyx_k_XQ_IQ_HF_q_uARwd_A_KvYa_G1D_Yav[] = "\320\004\035\230X\240Q\330\010\014\210I\220Q\340\010\014\210H\220F\230%\230q\240\002\240%\240u\250A\250R\250w\260d\270*\300A\340\010\014\210K\220v\230Y\240a\330\010\014\210G\2201\220D\230\005\230Y\240a\240v\250V\2601\260D\270\001\340\010\014\210G\2201\220D\230\005\230Y\240a\240t\250:\260V\2709\300A\300T\310\026\310w\320VW"; -static const char __pyx_k_a_IQ_F_E_as_q_6_vV1_q_E_4AT_fTZ[] = "\320\004\036\230a\330\010\020\220\004\220I\230Q\340\010\024\220F\230&\240\001\240\021\330\010\020\220\001\330\010\014\210E\220\025\220a\220s\230%\230q\240\010\250\002\250!\330\014\023\2206\230\031\240!\330\014\027\220v\230V\2401\330\014\020\220\007\220q\230\004\230E\320!4\260A\260T\270\032\300;\310f\320TZ\320Z[\320[_\320_e\320ek\320kl\320ls\320sy\320y\360\000\000@\002A\002\360\000\000A\002B\002\330\014\021\220\027\230\001\230\024\230V\2407\250!\330\014\020\220\005\220Y\230a\230v\240V\2501\250A\340\010\024\220F\230&\240\001\240\021\330\010\020\220\001\330\010\014\210E\220\025\220a\220s\230%\230q\240\010\250\002\250!\330\014\023\2206\230\031\240!\330\014\027\220v\230V\2401\330\014\020\220\007\220q\230\004\230E\320!4\260A\260T\270\032\300;\310f\320TZ\320Z[\320[_\320_e\320ek\320kl\320ls\320sy\320y\360\000\000@\002A\002\360\000\000A\002B\002\330\014\021\220\027\230\001\230\024\230V\2407\250!\330\014\020\220\005\220Y\230a\230v\240V\2501\250A\340\010\021\220\032\2307\240)\2501"; -static const char __pyx_k_a_t9Baq_1O_5_NR_a_M_1A_E_as_r_F[] = "\320\004\036\230a\330\010\017\210t\2209\230B\230a\230q\330\010\021\220\021\330\010\023\2201\220O\320#5\260_\300N\320R`\320`a\330\010\020\220\004\220M\240\022\2401\240A\330\010\014\210E\220\025\220a\220s\230%\230r\240\021\330\014\024\220F\230&\240\001\330\014\025\220V\2308\2401\240F\250)\2601\330\014\025\220V\2306\240\021\330\014\020\220\007\220q\230\004\230E\320!4\260A\260T\270\032\3006\310\026\310q\320PT\320TZ\320Z`\320`a\320ai\320io\320ou\320uv\320v\360\000\000@\002F\002\360\000\000F\002L\002\360\000\000L\002M\002\360\000\000M\002N\002\330\014\023\2206\230\027\240\003\2401\330\014\022\220)\2305\240\001\240\025\240g\250R\250q\330\014\020\220\005\220U\230!\2306\240\021\330\020\027\220x\230q\240\005\240V\2501\250A\330\014\022\220'\230\021\230!\330\014\020\220\005\220Y\230a\230v\240V\2501\250A\330\010\017\210q"; -static const char __pyx_k_a_t9Baq_d_1_M_1A_1HL_Kz_T_a_Q_E[] = "\320\004\036\230a\330\010\017\210t\2209\230B\230a\230q\330\010\026\220d\230&\240\002\240!\2401\330\010\020\220\004\220M\240\022\2401\240A\330\010\023\2201\220H\230L\250\014\260K\270z\310\033\320T`\320`a\330\010\r\210Q\340\010\014\210E\220\025\220a\220s\230%\230r\240\021\330\014\022\220)\2305\240\001\240\022\2402\240T\250\033\260A\330\014\020\220\005\220U\230!\2301\330\020\031\230\026\230x\240q\250\006\250i\260q\330\020\031\230\026\230v\240Q\330\020\024\220G\2301\230D\240\005\320%7\260q\270\004\270J\300c\310\023\310F\320RX\320XY\320Yb\320bh\320hn\320no\320op\330\020\027\220v\230W\240C\240s\250!\2501\330\020\035\230Q\330\020\024\220E\230\025\230a\230v\240Q\330\024\027\220x\230q\240\003\2403\240a\330\030\033\2306\240\021\240#\240S\250\001\330\034&\240a\240x\250q\260\006\260a\340\034&\240a\240x\250q\260\006\260a\330\030\031\330\024\036\230a\230x\240q\250\006\250f\260A\260Q\330\020\021\220\021\220)\2307\240!\2401\330\020\024\220E\230\031\240!\2406\250\026\250q\260\001\330\014\016\210g\220Q\220a\330\010\017\210q"; -static const char __pyx_k_e_Q_t7_q_iq_1_E_G1_RuE_E_auKuBa[] = "\320\000\026\220e\320\033,\320,=\270Q\330\004\007\200t\2107\220-\230q\240\001\330\010\016\210i\220q\230\002\320\0321\260\021\340\004\n\210\"\210E\220\030\230\021\230\"\230G\2401\340\004\r\210R\210u\220E\230\021\230\"\230E\240\025\240a\240u\250K\260u\270B\270a\330\004\013\2109\220A\220V\2308\2401\340\004\014\210E\220\022\2201\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\033\260A\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\033\260F\270\"\270A\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\031\260&\270\002\270!\330\004\n\210\"\210E\220\025\220a\220r\230\025\230e\2401\240E\250\031\260&\270\002\270!\330\004\016\210b\220\004\220F\230&\240\006\240a\340\004\013\2101\340\004\r\210R\210w\220a\220q\330\004\007\200w\210c\220\021\330\010\014\210A\320\r$\240A\340\010\014\210A\320\r$\240A\330\010\013\2101\330\014\024\220L\240\001\240\021\340\014\020\220\001\220\034\320\035/\250q\260\001\340\004\010\210\001\210\034\220[\240\001\240\021\340\004\013\2104\210v\220Q\220a"; -static const char __pyx_k_havWA_vQ_G1D__AT_6_qHXX_ddeef_v[] = "\320\004\032\230!\330\010\030\230\006\230h\240a\240v\250W\260A\330\010\021\220\026\220v\230Q\330\010\014\210G\2201\220D\230\005\230_\250A\250T\260\032\2706\300\026\300q\320HX\320X^\320^d\320de\320ef\330\010\017\210v\220W\230C\230q\330\010\023\2201\220H\230H\240H\250H\260A\330\010\020\220\001\330\010\014\210E\220\025\220a\220v\230Q\330\014\021\220\021\220(\230!\2306\240\035\250a\250q\330\010\014\210E\220\031\230!\2306\240\026\240q\250\001\330\010\017\210q"; -static const char __pyx_k_q_Q_E_as_fAQ_q_E_at_V6_fTZZ_gQa[] = "\320\004\027\220q\330\010\r\210Q\330\010\014\210E\220\025\220a\220s\230!\330\014\020\220\006\220f\230A\230Q\330\014\020\220\007\220q\230\004\230E\240\035\250a\250t\260:\270V\3006\310\021\310$\310f\320TZ\320Z[\320[\\\330\014\016\210g\220Q\220a\220q\330\010\014\210A\330\010\023\2201\320\024$\240O\3203C\3001\330\010\014\210E\220\025\220a\220q\330\014\r\210Q\210h\220a\220v\230R\230q\240\001\330\010\017\210q"; -static const char __pyx_k_q_q_wgXWG7_PQ_q_wa_q_wiq_3d_at6[] = "\320\004\027\220q\330\010\017\210q\220\007\220w\230g\240X\250W\260G\2707\300'\310\027\320PQ\330\010\017\210q\220\007\220w\230a\330\010\017\210q\220\010\230\007\230w\240i\250q\330\010\013\2103\210d\220&\230\006\230a\230t\2406\250\026\250q\260\004\260F\270&\300\001\300\021\330\010\r\210U\220&\230\006\230f\240D\250\006\250f\260D\270\006\270f\300A\330\010\014\210G\2201\220D\230\005\230]\250!\2504\250z\270\023\270F\300&\310\001\310\021\330\010\014\210G\2201\220D\230\005\230]\250!\2504\250z\270\023\270F\300&\310\001\310\021\330\010\014\210G\2201\220D\230\005\230]\250!\2504\250z\270\023\270F\300&\310\001\310\021\330\010\021\220\030\230\024\230Q\230c\240\031\250,\260d\270!\2703\270i\300{\320RV\320VW\320WZ\320Z["; -static const char __pyx_k_A_7_Rt7_Q_4uO1D_aq_5_1_B_2_6QQTT[] = "\200A\330\010\013\2107\220#\220R\220t\2307\240#\240Q\330\014\022\220&\230\t\240\021\330\014\023\2204\220u\230O\2501\250D\260\n\270&\300\006\300a\300q\330\014\023\2205\230\003\2301\340\014\024\220B\320\0262\260$\3206Q\320QT\320TZ\320Za\320ab\340\014\020\220\005\220Y\230a\230v\240V\2501\250A\340\014\022\220)\2301\230A"; -static const char __pyx_k_Note_that_Cython_is_deliberately[] = "Note that Cython is deliberately stricter than PEP-484 and rejects subclasses of builtin types. If you need to pass subclasses then set the 'annotation_typing' directive to False."; -/* #### Code section: decls ### */ -static PyObject *__pyx_pf_6epanet_6epanet__verify_platform(CYTHON_UNUSED PyObject *__pyx_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_path); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_2__del__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_4_check(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_result); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_6version(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_8net_size(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_10units(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_12times(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_14element_name(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_16energy_usage(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_18reactions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_20node_results(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_22link_results(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6Output_24dump(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_2_dump_output(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_4dump_output(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_6dump_report(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_8dump_output_binary(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_10run_project_return_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_name, PyObject *__pyx_v_readable_output); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_12run_project(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_name, PyObject *__pyx_v_readable_output); /* proto */ -static PyObject *__pyx_pf_6epanet_6epanet_14run_inp(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_name); /* proto */ -/* #### Code section: late_includes ### */ -/* #### Code section: module_state ### */ -/* SmallCodeConfig */ -#ifndef CYTHON_SMALL_CODE -#if defined(__clang__) - #define CYTHON_SMALL_CODE -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - #define CYTHON_SMALL_CODE __attribute__((cold)) -#else - #define CYTHON_SMALL_CODE -#endif -#endif - -typedef struct { - PyObject *__pyx_d; - PyObject *__pyx_b; - PyObject *__pyx_cython_runtime; - PyObject *__pyx_empty_tuple; - PyObject *__pyx_empty_bytes; - PyObject *__pyx_empty_unicode; - #ifdef __Pyx_CyFunction_USED - PyTypeObject *__pyx_CyFunctionType; - #endif - #ifdef __Pyx_FusedFunction_USED - PyTypeObject *__pyx_FusedFunctionType; - #endif - #ifdef __Pyx_Generator_USED - PyTypeObject *__pyx_GeneratorType; - #endif - #ifdef __Pyx_IterableCoroutine_USED - PyTypeObject *__pyx_IterableCoroutineType; - #endif - #ifdef __Pyx_Coroutine_USED - PyTypeObject *__pyx_CoroutineAwaitType; - #endif - #ifdef __Pyx_Coroutine_USED - PyTypeObject *__pyx_CoroutineType; - #endif - __Pyx_CachedCFunction __pyx_umethod_PyDict_Type_pop; - PyObject *__pyx_tuple[2]; - PyObject *__pyx_codeobj_tab[21]; - PyObject *__pyx_string_tab[249]; - PyObject *__pyx_float_2_0; - PyObject *__pyx_int_0; - PyObject *__pyx_int_1; - PyObject *__pyx_int_2; - PyObject *__pyx_int_3; - PyObject *__pyx_int_4; - PyObject *__pyx_int_5; - PyObject *__pyx_int_6; - PyObject *__pyx_int_10; -/* #### Code section: module_state_contents ### */ -/* CachedMethodType.module_state_decls */ -#if CYTHON_COMPILING_IN_LIMITED_API -PyObject *__Pyx_CachedMethodType; -#endif - -/* CodeObjectCache.module_state_decls */ -struct __Pyx_CodeObjectCache __pyx_code_cache; - -/* #### Code section: module_state_end ### */ -} __pyx_mstatetype; - -#if CYTHON_USE_MODULE_STATE -#ifdef __cplusplus -namespace { -extern struct PyModuleDef __pyx_moduledef; -} /* anonymous namespace */ -#else -static struct PyModuleDef __pyx_moduledef; -#endif - -#define __pyx_mstate_global (__Pyx_PyModule_GetState(__Pyx_State_FindModule(&__pyx_moduledef))) - -#define __pyx_m (__Pyx_State_FindModule(&__pyx_moduledef)) -#else -static __pyx_mstatetype __pyx_mstate_global_static = -#ifdef __cplusplus - {}; -#else - {0}; -#endif -static __pyx_mstatetype * const __pyx_mstate_global = &__pyx_mstate_global_static; -#endif -/* #### Code section: constant_name_defines ### */ -#define __pyx_kp_u_ __pyx_string_tab[0] -#define __pyx_kp_u_2 __pyx_string_tab[1] -#define __pyx_n_u_AFD __pyx_string_tab[2] -#define __pyx_n_u_Any __pyx_string_tab[3] -#define __pyx_n_u_AssertionError __pyx_string_tab[4] -#define __pyx_n_u_CDLL __pyx_string_tab[5] -#define __pyx_n_u_CFS __pyx_string_tab[6] -#define __pyx_n_u_CLOSED __pyx_string_tab[7] -#define __pyx_n_u_CMD __pyx_string_tab[8] -#define __pyx_n_u_CMH __pyx_string_tab[9] -#define __pyx_n_u_ENR_checkError __pyx_string_tab[10] -#define __pyx_n_u_ENR_close __pyx_string_tab[11] -#define __pyx_n_u_ENR_free __pyx_string_tab[12] -#define __pyx_n_u_ENR_getElementName __pyx_string_tab[13] -#define __pyx_n_u_ENR_getEnergyUsage __pyx_string_tab[14] -#define __pyx_n_u_ENR_getLinkResult __pyx_string_tab[15] -#define __pyx_n_u_ENR_getNetReacts __pyx_string_tab[16] -#define __pyx_n_u_ENR_getNetSize __pyx_string_tab[17] -#define __pyx_n_u_ENR_getNodeResult __pyx_string_tab[18] -#define __pyx_n_u_ENR_getTimes __pyx_string_tab[19] -#define __pyx_n_u_ENR_getUnits __pyx_string_tab[20] -#define __pyx_n_u_ENR_getVersion __pyx_string_tab[21] -#define __pyx_n_u_ENR_init __pyx_string_tab[22] -#define __pyx_n_u_ENR_open __pyx_string_tab[23] -#define __pyx_kp_u_Failed_to_read_project __pyx_string_tab[24] -#define __pyx_n_u_GPM __pyx_string_tab[25] -#define __pyx_n_u_HOURS __pyx_string_tab[26] -#define __pyx_n_u_IMGD __pyx_string_tab[27] -#define __pyx_n_u_KPA __pyx_string_tab[28] -#define __pyx_n_u_LPM __pyx_string_tab[29] -#define __pyx_n_u_LPS __pyx_string_tab[30] -#define __pyx_n_u_MGD __pyx_string_tab[31] -#define __pyx_n_u_MGL __pyx_string_tab[32] -#define __pyx_n_u_MLD __pyx_string_tab[33] -#define __pyx_n_u_MTR __pyx_string_tab[34] -#define __pyx_n_u_NONE __pyx_string_tab[35] -#define __pyx_n_u_None __pyx_string_tab[36] -#define __pyx_kp_u_Not_found_project __pyx_string_tab[37] -#define __pyx_kp_u_Note_that_Cython_is_deliberately __pyx_string_tab[38] -#define __pyx_n_u_OPEN __pyx_string_tab[39] -#define __pyx_n_u_Output __pyx_string_tab[40] -#define __pyx_n_u_Output___del __pyx_string_tab[41] -#define __pyx_n_u_Output___init __pyx_string_tab[42] -#define __pyx_n_u_Output__check __pyx_string_tab[43] -#define __pyx_n_u_Output_dump __pyx_string_tab[44] -#define __pyx_n_u_Output_element_name __pyx_string_tab[45] -#define __pyx_n_u_Output_energy_usage __pyx_string_tab[46] -#define __pyx_n_u_Output_link_results __pyx_string_tab[47] -#define __pyx_n_u_Output_net_size __pyx_string_tab[48] -#define __pyx_n_u_Output_node_results __pyx_string_tab[49] -#define __pyx_n_u_Output_reactions __pyx_string_tab[50] -#define __pyx_n_u_Output_times __pyx_string_tab[51] -#define __pyx_n_u_Output_units __pyx_string_tab[52] -#define __pyx_n_u_Output_version __pyx_string_tab[53] -#define __pyx_n_u_POINTER __pyx_string_tab[54] -#define __pyx_n_u_PRCNT __pyx_string_tab[55] -#define __pyx_n_u_PSI __pyx_string_tab[56] -#define __pyx_kp_u_Platform __pyx_string_tab[57] -#define __pyx_n_u_UGL __pyx_string_tab[58] -#define __pyx_n_u_Windows __pyx_string_tab[59] -#define __pyx_kp_u__2 __pyx_string_tab[60] -#define __pyx_kp_u__3 __pyx_string_tab[61] -#define __pyx_kp_u__4 __pyx_string_tab[62] -#define __pyx_kp_u__5 __pyx_string_tab[63] -#define __pyx_n_u_abspath __pyx_string_tab[64] -#define __pyx_kp_u_add_note __pyx_string_tab[65] -#define __pyx_n_u_api __pyx_string_tab[66] -#define __pyx_n_u_append __pyx_string_tab[67] -#define __pyx_n_u_asyncio_coroutines __pyx_string_tab[68] -#define __pyx_n_u_attributes __pyx_string_tab[69] -#define __pyx_kp_u_avg_efficiency __pyx_string_tab[70] -#define __pyx_kp_u_avg_kW_flow __pyx_string_tab[71] -#define __pyx_kp_u_avg_kwatts __pyx_string_tab[72] -#define __pyx_n_u_b64encode __pyx_string_tab[73] -#define __pyx_n_u_base64 __pyx_string_tab[74] -#define __pyx_n_u_bast64_data __pyx_string_tab[75] -#define __pyx_n_u_bool __pyx_string_tab[76] -#define __pyx_n_u_bulk __pyx_string_tab[77] -#define __pyx_n_u_byref __pyx_string_tab[78] -#define __pyx_n_u_c_char_p __pyx_string_tab[79] -#define __pyx_n_u_c_float __pyx_string_tab[80] -#define __pyx_n_u_c_int __pyx_string_tab[81] -#define __pyx_n_u_c_void_p __pyx_string_tab[82] -#define __pyx_n_u_category __pyx_string_tab[83] -#define __pyx_n_u_check __pyx_string_tab[84] -#define __pyx_n_u_class_getitem __pyx_string_tab[85] -#define __pyx_n_u_cline_in_traceback __pyx_string_tab[86] -#define __pyx_n_u_code __pyx_string_tab[87] -#define __pyx_n_u_command __pyx_string_tab[88] -#define __pyx_kp_u_cost_day __pyx_string_tab[89] -#define __pyx_n_u_ctypes __pyx_string_tab[90] -#define __pyx_n_u_d __pyx_string_tab[91] -#define __pyx_n_u_data __pyx_string_tab[92] -#define __pyx_kp_u_db __pyx_string_tab[93] -#define __pyx_n_u_db_inp __pyx_string_tab[94] -#define __pyx_kp_u_db_inp_2 __pyx_string_tab[95] -#define __pyx_n_u_decode __pyx_string_tab[96] -#define __pyx_n_u_del __pyx_string_tab[97] -#define __pyx_n_u_demand __pyx_string_tab[98] -#define __pyx_kp_u_dict_str_Any __pyx_string_tab[99] -#define __pyx_kp_u_dict_str_float __pyx_string_tab[100] -#define __pyx_kp_u_dict_str_int __pyx_string_tab[101] -#define __pyx_kp_u_dict_str_list_str __pyx_string_tab[102] -#define __pyx_kp_u_dict_str_str __pyx_string_tab[103] -#define __pyx_n_u_dir __pyx_string_tab[104] -#define __pyx_n_u_doc __pyx_string_tab[105] -#define __pyx_n_u_ds __pyx_string_tab[106] -#define __pyx_n_u_dump __pyx_string_tab[107] -#define __pyx_n_u_dump_inp __pyx_string_tab[108] -#define __pyx_n_u_dump_output __pyx_string_tab[109] -#define __pyx_n_u_dump_output_2 __pyx_string_tab[110] -#define __pyx_n_u_dump_output_binary __pyx_string_tab[111] -#define __pyx_n_u_dump_report __pyx_string_tab[112] -#define __pyx_n_u_dumps __pyx_string_tab[113] -#define __pyx_n_u_element_count __pyx_string_tab[114] -#define __pyx_n_u_element_name __pyx_string_tab[115] -#define __pyx_n_u_encode __pyx_string_tab[116] -#define __pyx_n_u_energy_usage __pyx_string_tab[117] -#define __pyx_n_u_enter __pyx_string_tab[118] -#define __pyx_n_u_epanet __pyx_string_tab[119] -#define __pyx_n_u_epanet_epanet __pyx_string_tab[120] -#define __pyx_kp_u_epanet_epanet_py __pyx_string_tab[121] -#define __pyx_kp_u_epanet_output_dll __pyx_string_tab[122] -#define __pyx_n_u_error __pyx_string_tab[123] -#define __pyx_n_u_exe __pyx_string_tab[124] -#define __pyx_n_u_exit __pyx_string_tab[125] -#define __pyx_n_u_f __pyx_string_tab[126] -#define __pyx_n_u_f_u __pyx_string_tab[127] -#define __pyx_n_u_f_us __pyx_string_tab[128] -#define __pyx_n_u_failed __pyx_string_tab[129] -#define __pyx_n_u_flow __pyx_string_tab[130] -#define __pyx_n_u_friction __pyx_string_tab[131] -#define __pyx_n_u_func __pyx_string_tab[132] -#define __pyx_n_u_getcwd __pyx_string_tab[133] -#define __pyx_n_u_handle __pyx_string_tab[134] -#define __pyx_n_u_have_project __pyx_string_tab[135] -#define __pyx_n_u_head __pyx_string_tab[136] -#define __pyx_n_u_headloss __pyx_string_tab[137] -#define __pyx_n_u_i __pyx_string_tab[138] -#define __pyx_n_u_index __pyx_string_tab[139] -#define __pyx_n_u_init __pyx_string_tab[140] -#define __pyx_n_u_initializing __pyx_string_tab[141] -#define __pyx_kp_u_inp __pyx_string_tab[142] -#define __pyx_n_u_inp_2 __pyx_string_tab[143] -#define __pyx_n_u_inp_out __pyx_string_tab[144] -#define __pyx_n_u_input __pyx_string_tab[145] -#define __pyx_n_u_int __pyx_string_tab[146] -#define __pyx_n_u_is_coroutine __pyx_string_tab[147] -#define __pyx_n_u_j __pyx_string_tab[148] -#define __pyx_n_u_join __pyx_string_tab[149] -#define __pyx_kp_u_json __pyx_string_tab[150] -#define __pyx_n_u_json_2 __pyx_string_tab[151] -#define __pyx_n_u_k __pyx_string_tab[152] -#define __pyx_n_u_length __pyx_string_tab[153] -#define __pyx_n_u_lib __pyx_string_tab[154] -#define __pyx_n_u_link __pyx_string_tab[155] -#define __pyx_n_u_link_results __pyx_string_tab[156] -#define __pyx_n_u_link_type __pyx_string_tab[157] -#define __pyx_n_u_links __pyx_string_tab[158] -#define __pyx_kp_u_list_dict_str_Any __pyx_string_tab[159] -#define __pyx_n_u_main __pyx_string_tab[160] -#define __pyx_kp_u_max_kwatts __pyx_string_tab[161] -#define __pyx_n_u_metaclass __pyx_string_tab[162] -#define __pyx_n_u_module __pyx_string_tab[163] -#define __pyx_n_u_msg __pyx_string_tab[164] -#define __pyx_n_u_name __pyx_string_tab[165] -#define __pyx_n_u_name_2 __pyx_string_tab[166] -#define __pyx_n_u_name_len __pyx_string_tab[167] -#define __pyx_n_u_net_size __pyx_string_tab[168] -#define __pyx_n_u_node __pyx_string_tab[169] -#define __pyx_n_u_node_results __pyx_string_tab[170] -#define __pyx_n_u_node_type __pyx_string_tab[171] -#define __pyx_n_u_nodes __pyx_string_tab[172] -#define __pyx_n_u_num_periods __pyx_string_tab[173] -#define __pyx_n_u_open __pyx_string_tab[174] -#define __pyx_kp_u_opt __pyx_string_tab[175] -#define __pyx_n_u_opt_2 __pyx_string_tab[176] -#define __pyx_n_u_os __pyx_string_tab[177] -#define __pyx_n_u_output __pyx_string_tab[178] -#define __pyx_kp_u_output_message __pyx_string_tab[179] -#define __pyx_n_u_p __pyx_string_tab[180] -#define __pyx_n_u_p_u __pyx_string_tab[181] -#define __pyx_n_u_p_us __pyx_string_tab[182] -#define __pyx_n_u_path __pyx_string_tab[183] -#define __pyx_n_u_path_2 __pyx_string_tab[184] -#define __pyx_n_u_platform __pyx_string_tab[185] -#define __pyx_n_u_platform_2 __pyx_string_tab[186] -#define __pyx_n_u_pop __pyx_string_tab[187] -#define __pyx_n_u_prepare __pyx_string_tab[188] -#define __pyx_n_u_pressure __pyx_string_tab[189] -#define __pyx_n_u_project __pyx_string_tab[190] -#define __pyx_n_u_pump __pyx_string_tab[191] -#define __pyx_n_u_q __pyx_string_tab[192] -#define __pyx_n_u_q_u __pyx_string_tab[193] -#define __pyx_n_u_q_us __pyx_string_tab[194] -#define __pyx_n_u_quality __pyx_string_tab[195] -#define __pyx_n_u_qualname __pyx_string_tab[196] -#define __pyx_n_u_r __pyx_string_tab[197] -#define __pyx_n_u_range __pyx_string_tab[198] -#define __pyx_n_u_rb __pyx_string_tab[199] -#define __pyx_n_u_reaction __pyx_string_tab[200] -#define __pyx_n_u_reactions __pyx_string_tab[201] -#define __pyx_n_u_read __pyx_string_tab[202] -#define __pyx_n_u_readable_output __pyx_string_tab[203] -#define __pyx_n_u_report __pyx_string_tab[204] -#define __pyx_n_u_report_start __pyx_string_tab[205] -#define __pyx_n_u_report_step __pyx_string_tab[206] -#define __pyx_n_u_result __pyx_string_tab[207] -#define __pyx_n_u_return __pyx_string_tab[208] -#define __pyx_kp_u_rpt __pyx_string_tab[209] -#define __pyx_n_u_rpt_2 __pyx_string_tab[210] -#define __pyx_n_u_run_inp __pyx_string_tab[211] -#define __pyx_n_u_run_project __pyx_string_tab[212] -#define __pyx_n_u_run_project_return_dict __pyx_string_tab[213] -#define __pyx_kp_u_runepanet_exe __pyx_string_tab[214] -#define __pyx_n_u_self __pyx_string_tab[215] -#define __pyx_n_u_setting __pyx_string_tab[216] -#define __pyx_n_u_sim_duration __pyx_string_tab[217] -#define __pyx_n_u_simulation_result __pyx_string_tab[218] -#define __pyx_n_u_size __pyx_string_tab[219] -#define __pyx_n_u_sizes __pyx_string_tab[220] -#define __pyx_n_u_source __pyx_string_tab[221] -#define __pyx_n_u_spec __pyx_string_tab[222] -#define __pyx_n_u_status __pyx_string_tab[223] -#define __pyx_n_u_str __pyx_string_tab[224] -#define __pyx_n_u_successful __pyx_string_tab[225] -#define __pyx_n_u_sys __pyx_string_tab[226] -#define __pyx_n_u_system __pyx_string_tab[227] -#define __pyx_n_u_t __pyx_string_tab[228] -#define __pyx_n_u_tank __pyx_string_tab[229] -#define __pyx_n_u_temp __pyx_string_tab[230] -#define __pyx_n_u_test __pyx_string_tab[231] -#define __pyx_n_u_times __pyx_string_tab[232] -#define __pyx_n_u_ts __pyx_string_tab[233] -#define __pyx_n_u_typing __pyx_string_tab[234] -#define __pyx_n_u_units __pyx_string_tab[235] -#define __pyx_kp_u_unsupported_not_yet __pyx_string_tab[236] -#define __pyx_n_u_usages __pyx_string_tab[237] -#define __pyx_kp_u_utf_8 __pyx_string_tab[238] -#define __pyx_n_u_utilization __pyx_string_tab[239] -#define __pyx_n_u_v __pyx_string_tab[240] -#define __pyx_n_u_value __pyx_string_tab[241] -#define __pyx_n_u_values __pyx_string_tab[242] -#define __pyx_n_u_valve __pyx_string_tab[243] -#define __pyx_n_u_velocity __pyx_string_tab[244] -#define __pyx_n_u_verify_platform __pyx_string_tab[245] -#define __pyx_n_u_version __pyx_string_tab[246] -#define __pyx_n_u_w __pyx_string_tab[247] -#define __pyx_n_u_wall __pyx_string_tab[248] -/* #### Code section: module_state_clear ### */ -#if CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __pyx_m_clear(PyObject *m) { - __pyx_mstatetype *clear_module_state = __Pyx_PyModule_GetState(m); - if (!clear_module_state) return 0; - Py_CLEAR(clear_module_state->__pyx_d); - Py_CLEAR(clear_module_state->__pyx_b); - Py_CLEAR(clear_module_state->__pyx_cython_runtime); - Py_CLEAR(clear_module_state->__pyx_empty_tuple); - Py_CLEAR(clear_module_state->__pyx_empty_bytes); - Py_CLEAR(clear_module_state->__pyx_empty_unicode); - #ifdef __Pyx_CyFunction_USED - Py_CLEAR(clear_module_state->__pyx_CyFunctionType); - #endif - #ifdef __Pyx_FusedFunction_USED - Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); - #endif - #if CYTHON_PEP489_MULTI_PHASE_INIT - __Pyx_State_RemoveModule(NULL); - #endif - for (int i=0; i<2; ++i) { Py_CLEAR(clear_module_state->__pyx_tuple[i]); } - for (int i=0; i<21; ++i) { Py_CLEAR(clear_module_state->__pyx_codeobj_tab[i]); } - for (int i=0; i<249; ++i) { Py_CLEAR(clear_module_state->__pyx_string_tab[i]); } - Py_CLEAR(clear_module_state->__pyx_float_2_0); - Py_CLEAR(clear_module_state->__pyx_int_0); - Py_CLEAR(clear_module_state->__pyx_int_1); - Py_CLEAR(clear_module_state->__pyx_int_2); - Py_CLEAR(clear_module_state->__pyx_int_3); - Py_CLEAR(clear_module_state->__pyx_int_4); - Py_CLEAR(clear_module_state->__pyx_int_5); - Py_CLEAR(clear_module_state->__pyx_int_6); - Py_CLEAR(clear_module_state->__pyx_int_10); - return 0; -} -#endif -/* #### Code section: module_state_traverse ### */ -#if CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { - __pyx_mstatetype *traverse_module_state = __Pyx_PyModule_GetState(m); - if (!traverse_module_state) return 0; - Py_VISIT(traverse_module_state->__pyx_d); - Py_VISIT(traverse_module_state->__pyx_b); - Py_VISIT(traverse_module_state->__pyx_cython_runtime); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_tuple); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_bytes); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_unicode); - #ifdef __Pyx_CyFunction_USED - Py_VISIT(traverse_module_state->__pyx_CyFunctionType); - #endif - #ifdef __Pyx_FusedFunction_USED - Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); - #endif - for (int i=0; i<2; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_tuple[i]); } - for (int i=0; i<21; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_codeobj_tab[i]); } - for (int i=0; i<249; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_string_tab[i]); } - __Pyx_VISIT_CONST(traverse_module_state->__pyx_float_2_0); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_0); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_1); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_2); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_3); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_4); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_5); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_6); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_int_10); - return 0; -} -#endif -/* #### Code section: module_code ### */ - -/* "epanet/epanet.py":13 - * - * - * def _verify_platform(): # <<<<<<<<<<<<<< - * _platform = platform.system() - * if _platform != "Windows": -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_1_verify_platform(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_1_verify_platform = {"_verify_platform", (PyCFunction)__pyx_pw_6epanet_6epanet_1_verify_platform, METH_NOARGS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_1_verify_platform(PyObject *__pyx_self, CYTHON_UNUSED PyObject *unused) { - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("_verify_platform (wrapper)", 0); - __pyx_kwvalues = __Pyx_KwValues_VARARGS(__pyx_args, __pyx_nargs); - __pyx_r = __pyx_pf_6epanet_6epanet__verify_platform(__pyx_self); - - /* function exit code */ - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet__verify_platform(CYTHON_UNUSED PyObject *__pyx_self) { - PyObject *__pyx_v__platform = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - size_t __pyx_t_5; - int __pyx_t_6; - PyObject *__pyx_t_7[3]; - PyObject *__pyx_t_8 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("_verify_platform", 0); - - /* "epanet/epanet.py":14 - * - * def _verify_platform(): - * _platform = platform.system() # <<<<<<<<<<<<<< - * if _platform != "Windows": - * raise Exception(f'Platform {_platform} unsupported (not yet)') -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_platform); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_system); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (1-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v__platform = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":15 - * def _verify_platform(): - * _platform = platform.system() - * if _platform != "Windows": # <<<<<<<<<<<<<< - * raise Exception(f'Platform {_platform} unsupported (not yet)') - * -*/ - __pyx_t_6 = (__Pyx_PyUnicode_Equals(__pyx_v__platform, __pyx_mstate_global->__pyx_n_u_Windows, Py_NE)); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 15, __pyx_L1_error) - if (unlikely(__pyx_t_6)) { - - /* "epanet/epanet.py":16 - * _platform = platform.system() - * if _platform != "Windows": - * raise Exception(f'Platform {_platform} unsupported (not yet)') # <<<<<<<<<<<<<< - * - * -*/ - __pyx_t_4 = NULL; - __Pyx_INCREF((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_2 = ((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_3 = __Pyx_PyObject_FormatSimple(__pyx_v__platform, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_7[0] = __pyx_mstate_global->__pyx_kp_u_Platform; - __pyx_t_7[1] = __pyx_t_3; - __pyx_t_7[2] = __pyx_mstate_global->__pyx_kp_u_unsupported_not_yet; - __pyx_t_8 = __Pyx_PyUnicode_Join(__pyx_t_7, 3, 9 + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_3) + 22, 127 | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_3)); - if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_8}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_Raise(__pyx_t_1, 0, 0, 0); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __PYX_ERR(0, 16, __pyx_L1_error) - - /* "epanet/epanet.py":15 - * def _verify_platform(): - * _platform = platform.system() - * if _platform != "Windows": # <<<<<<<<<<<<<< - * raise Exception(f'Platform {_platform} unsupported (not yet)') - * -*/ - } - - /* "epanet/epanet.py":13 - * - * - * def _verify_platform(): # <<<<<<<<<<<<<< - * _platform = platform.system() - * if _platform != "Windows": -*/ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_AddTraceback("epanet.epanet._verify_platform", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v__platform); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":24 - * - * class Output: - * def __init__(self, path: str) -> None: # <<<<<<<<<<<<<< - * self._path = path - * -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_1__init__(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_1__init__ = {"__init__", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_1__init__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_1__init__(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - PyObject *__pyx_v_path = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[2] = {0,0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__init__ (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,&__pyx_mstate_global->__pyx_n_u_path,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 24, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 2: - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 24, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 24, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "__init__", 0) < 0) __PYX_ERR(0, 24, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 2; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("__init__", 1, 2, 2, i); __PYX_ERR(0, 24, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 2)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 24, __pyx_L3_error) - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 24, __pyx_L3_error) - } - __pyx_v_self = values[0]; - __pyx_v_path = ((PyObject*)values[1]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 24, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_path), (&PyUnicode_Type), 0, "path", 2))) __PYX_ERR(0, 24, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_6Output___init__(__pyx_self, __pyx_v_self, __pyx_v_path); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output___init__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_path) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - size_t __pyx_t_11; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__init__", 0); - - /* "epanet/epanet.py":25 - * class Output: - * def __init__(self, path: str) -> None: - * self._path = path # <<<<<<<<<<<<<< - * - * self._lib = ctypes.CDLL(os.path.join(os.getcwd(), 'epanet', 'epanet-output.dll')) -*/ - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_path_2, __pyx_v_path) < 0) __PYX_ERR(0, 25, __pyx_L1_error) - - /* "epanet/epanet.py":27 - * self._path = path - * - * self._lib = ctypes.CDLL(os.path.join(os.getcwd(), 'epanet', 'epanet-output.dll')) # <<<<<<<<<<<<<< - * - * self._handle = ctypes.c_void_p() -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_CDLL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_5 = __pyx_t_7; - __Pyx_INCREF(__pyx_t_5); - __pyx_t_8 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_getcwd); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_11 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_10))) { - __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_10); - assert(__pyx_t_8); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_10); - __Pyx_INCREF(__pyx_t_8); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_10, __pyx__function); - __pyx_t_11 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_8, NULL}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+__pyx_t_11, (1-__pyx_t_11) | (__pyx_t_11*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_t_11 = 0; - { - PyObject *__pyx_callargs[4] = {__pyx_t_5, __pyx_t_6, __pyx_mstate_global->__pyx_n_u_epanet, __pyx_mstate_global->__pyx_kp_u_epanet_output_dll}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_11, (4-__pyx_t_11) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_11 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_11 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_11, (2-__pyx_t_11) | (__pyx_t_11*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib, __pyx_t_1) < 0) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":29 - * self._lib = ctypes.CDLL(os.path.join(os.getcwd(), 'epanet', 'epanet-output.dll')) - * - * self._handle = ctypes.c_void_p() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_init(ctypes.byref(self._handle))) - * -*/ - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 29, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_c_void_p); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 29, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_11 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_2))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_2); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_2, __pyx__function); - __pyx_t_11 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_11, (1-__pyx_t_11) | (__pyx_t_11*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 29, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (__Pyx_PyObject_SetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle, __pyx_t_1) < 0) __PYX_ERR(0, 29, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":30 - * - * self._handle = ctypes.c_void_p() - * self._check(self._lib.ENR_init(ctypes.byref(self._handle))) # <<<<<<<<<<<<<< - * - * self._check(self._lib.ENR_open(self._handle, ctypes.c_char_p(self._path.encode()))) -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_3 = __pyx_t_7; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_5 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_8))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_8); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_8); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_8, __pyx__function); - __pyx_t_11 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_10}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_8, __pyx_callargs+__pyx_t_11, (2-__pyx_t_11) | (__pyx_t_11*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_t_11 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_t_6}; - __pyx_t_4 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_init, __pyx_callargs+__pyx_t_11, (2-__pyx_t_11) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - __pyx_t_11 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_t_4}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_11, (2-__pyx_t_11) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":32 - * self._check(self._lib.ENR_init(ctypes.byref(self._handle))) - * - * self._check(self._lib.ENR_open(self._handle, ctypes.c_char_p(self._path.encode()))) # <<<<<<<<<<<<<< - * - * -*/ - __pyx_t_4 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __pyx_t_6; - __Pyx_INCREF(__pyx_t_7); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_c_char_p); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_path_2); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_12 = __pyx_t_13; - __Pyx_INCREF(__pyx_t_12); - __pyx_t_11 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, NULL}; - __pyx_t_5 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_encode, __pyx_callargs+__pyx_t_11, (1-__pyx_t_11) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - } - __pyx_t_11 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_9))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_9); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); - __pyx_t_11 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_t_5}; - __pyx_t_8 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_11, (2-__pyx_t_11) | (__pyx_t_11*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - } - __pyx_t_11 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_7, __pyx_t_3, __pyx_t_8}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_open, __pyx_callargs+__pyx_t_11, (3-__pyx_t_11) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_11 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_2}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_11, (2-__pyx_t_11) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":24 - * - * class Output: - * def __init__(self, path: str) -> None: # <<<<<<<<<<<<<< - * self._path = path - * -*/ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_XDECREF(__pyx_t_13); - __Pyx_AddTraceback("epanet.epanet.Output.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":35 - * - * - * def __del__(self): # <<<<<<<<<<<<<< - * # throw exception in destructor ? :) - * self._check(self._lib.ENR_close(ctypes.byref(self._handle))) -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_3__del__(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_3__del__ = {"__del__", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_3__del__, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_3__del__(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("__del__ (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 35, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 35, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "__del__", 0) < 0) __PYX_ERR(0, 35, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("__del__", 1, 1, 1, i); __PYX_ERR(0, 35, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 35, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__del__", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 35, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.__del__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_2__del__(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_2__del__(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - size_t __pyx_t_10; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("__del__", 0); - - /* "epanet/epanet.py":37 - * def __del__(self): - * # throw exception in destructor ? :) - * self._check(self._lib.ENR_close(ctypes.byref(self._handle))) # <<<<<<<<<<<<<< - * - * -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = __pyx_t_5; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_7 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_10 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_9))) { - __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_9); - assert(__pyx_t_7); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); - __Pyx_INCREF(__pyx_t_7); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); - __pyx_t_10 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_t_8}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (__pyx_t_10*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_t_10 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_6}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_close, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_10 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":35 - * - * - * def __del__(self): # <<<<<<<<<<<<<< - * # throw exception in destructor ? :) - * self._check(self._lib.ENR_close(ctypes.byref(self._handle))) -*/ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_AddTraceback("epanet.epanet.Output.__del__", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":40 - * - * - * def _check(self, result): # <<<<<<<<<<<<<< - * if result != 0 and result != 10: - * msg = ctypes.c_char_p() -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_5_check(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_5_check = {"_check", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_5_check, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_5_check(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - PyObject *__pyx_v_result = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[2] = {0,0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("_check (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,&__pyx_mstate_global->__pyx_n_u_result,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 40, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 2: - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 40, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 40, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "_check", 0) < 0) __PYX_ERR(0, 40, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 2; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("_check", 1, 2, 2, i); __PYX_ERR(0, 40, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 2)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 40, __pyx_L3_error) - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 40, __pyx_L3_error) - } - __pyx_v_self = values[0]; - __pyx_v_result = values[1]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("_check", 1, 2, 2, __pyx_nargs); __PYX_ERR(0, 40, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output._check", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_4_check(__pyx_self, __pyx_v_self, __pyx_v_result); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_4_check(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self, PyObject *__pyx_v_result) { - PyObject *__pyx_v_msg = NULL; - PyObject *__pyx_v_code = NULL; - PyObject *__pyx_v_error = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - int __pyx_t_1; - int __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - size_t __pyx_t_7; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12[5]; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("_check", 0); - - /* "epanet/epanet.py":41 - * - * def _check(self, result): - * if result != 0 and result != 10: # <<<<<<<<<<<<<< - * msg = ctypes.c_char_p() - * code = self._lib.ENR_checkError(self._handle, ctypes.byref(msg)) -*/ - __pyx_t_2 = (__Pyx_PyLong_BoolNeObjC(__pyx_v_result, __pyx_mstate_global->__pyx_int_0, 0, 0)); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 41, __pyx_L1_error) - if (__pyx_t_2) { - } else { - __pyx_t_1 = __pyx_t_2; - goto __pyx_L4_bool_binop_done; - } - __pyx_t_2 = (__Pyx_PyLong_BoolNeObjC(__pyx_v_result, __pyx_mstate_global->__pyx_int_10, 10, 0)); if (unlikely((__pyx_t_2 < 0))) __PYX_ERR(0, 41, __pyx_L1_error) - __pyx_t_1 = __pyx_t_2; - __pyx_L4_bool_binop_done:; - if (unlikely(__pyx_t_1)) { - - /* "epanet/epanet.py":42 - * def _check(self, result): - * if result != 0 and result != 10: - * msg = ctypes.c_char_p() # <<<<<<<<<<<<<< - * code = self._lib.ENR_checkError(self._handle, ctypes.byref(msg)) - * assert code == result -*/ - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 42, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_c_char_p); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 42, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_7 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_7 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_7, (1-__pyx_t_7) | (__pyx_t_7*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 42, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_v_msg = __pyx_t_3; - __pyx_t_3 = 0; - - /* "epanet/epanet.py":43 - * if result != 0 and result != 10: - * msg = ctypes.c_char_p() - * code = self._lib.ENR_checkError(self._handle, ctypes.byref(msg)) # <<<<<<<<<<<<<< - * assert code == result - * -*/ - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 43, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_6 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_6); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 43, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 43, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 43, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_7 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_7 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_v_msg}; - __pyx_t_8 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_7, (2-__pyx_t_7) | (__pyx_t_7*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 43, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - } - __pyx_t_7 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_6, __pyx_t_5, __pyx_t_8}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_checkError, __pyx_callargs+__pyx_t_7, (3-__pyx_t_7) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 43, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_v_code = __pyx_t_3; - __pyx_t_3 = 0; - - /* "epanet/epanet.py":44 - * msg = ctypes.c_char_p() - * code = self._lib.ENR_checkError(self._handle, ctypes.byref(msg)) - * assert code == result # <<<<<<<<<<<<<< - * - * error = f'Failed to read project [{self._path}] output, message [{msg.value.decode()}]' -*/ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(__pyx_assertions_enabled())) { - __pyx_t_3 = PyObject_RichCompare(__pyx_v_code, __pyx_v_result, Py_EQ); __Pyx_XGOTREF(__pyx_t_3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 44, __pyx_L1_error) - __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 44, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) { - __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); - __PYX_ERR(0, 44, __pyx_L1_error) - } - } - #else - if ((1)); else __PYX_ERR(0, 44, __pyx_L1_error) - #endif - - /* "epanet/epanet.py":46 - * assert code == result - * - * error = f'Failed to read project [{self._path}] output, message [{msg.value.decode()}]' # <<<<<<<<<<<<<< - * - * self._lib.ENR_free(ctypes.byref(msg)) -*/ - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_path_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_t_3, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_msg, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_decode); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = __Pyx_PyObject_CallNoArg(__pyx_t_8); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_t_8 = __Pyx_PyObject_FormatSimple(__pyx_t_3, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_12[0] = __pyx_mstate_global->__pyx_kp_u_Failed_to_read_project; - __pyx_t_12[1] = __pyx_t_4; - __pyx_t_12[2] = __pyx_mstate_global->__pyx_kp_u_output_message; - __pyx_t_12[3] = __pyx_t_8; - __pyx_t_12[4] = __pyx_mstate_global->__pyx_kp_u_; - __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_12, 5, 24 + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4) + 19 + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_8) + 1, 127 | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_4) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_8)); - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_v_error = ((PyObject*)__pyx_t_3); - __pyx_t_3 = 0; - - /* "epanet/epanet.py":48 - * error = f'Failed to read project [{self._path}] output, message [{msg.value.decode()}]' - * - * self._lib.ENR_free(ctypes.byref(msg)) # <<<<<<<<<<<<<< - * - * raise Exception(error) -*/ - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 48, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_8 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_8); - __pyx_t_6 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 48, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 48, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_7 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_9))) { - __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_9); - assert(__pyx_t_6); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); - __Pyx_INCREF(__pyx_t_6); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); - __pyx_t_7 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_v_msg}; - __pyx_t_5 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_7, (2-__pyx_t_7) | (__pyx_t_7*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 48, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - } - __pyx_t_7 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_8, __pyx_t_5}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_7, (2-__pyx_t_7) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 48, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":50 - * self._lib.ENR_free(ctypes.byref(msg)) - * - * raise Exception(error) # <<<<<<<<<<<<<< - * - * -*/ - __pyx_t_4 = NULL; - __Pyx_INCREF((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_5 = ((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_7 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_v_error}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_7, (2-__pyx_t_7) | (__pyx_t_7*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 50, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __Pyx_Raise(__pyx_t_3, 0, 0, 0); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __PYX_ERR(0, 50, __pyx_L1_error) - - /* "epanet/epanet.py":41 - * - * def _check(self, result): - * if result != 0 and result != 10: # <<<<<<<<<<<<<< - * msg = ctypes.c_char_p() - * code = self._lib.ENR_checkError(self._handle, ctypes.byref(msg)) -*/ - } - - /* "epanet/epanet.py":40 - * - * - * def _check(self, result): # <<<<<<<<<<<<<< - * if result != 0 and result != 10: - * msg = ctypes.c_char_p() -*/ - - /* function exit code */ - __pyx_r = Py_None; __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_AddTraceback("epanet.epanet.Output._check", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_msg); - __Pyx_XDECREF(__pyx_v_code); - __Pyx_XDECREF(__pyx_v_error); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":53 - * - * - * def version(self) -> int: # <<<<<<<<<<<<<< - * v = ctypes.c_int() - * self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_7version(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_7version = {"version", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_7version, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_7version(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("version (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 53, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 53, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "version", 0) < 0) __PYX_ERR(0, 53, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("version", 1, 1, 1, i); __PYX_ERR(0, 53, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 53, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("version", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 53, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.version", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_6version(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_6version(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_v = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - size_t __pyx_t_5; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("version", 0); - - /* "epanet/epanet.py":54 - * - * def version(self) -> int: - * v = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) - * return v.value -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 54, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 54, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (1-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 54, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_v = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":55 - * def version(self) -> int: - * v = ctypes.c_int() - * self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) # <<<<<<<<<<<<<< - * return v.value - * -*/ - __pyx_t_4 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_3 = __pyx_t_6; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_v_v}; - __pyx_t_8 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_7, __pyx_t_8}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getVersion, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_2}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":56 - * v = ctypes.c_int() - * self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) - * return v.value # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_v, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 56, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (!(likely(PyLong_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None) || __Pyx_RaiseUnexpectedTypeError("int", __pyx_t_1))) __PYX_ERR(0, 56, __pyx_L1_error) - __pyx_r = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "epanet/epanet.py":53 - * - * - * def version(self) -> int: # <<<<<<<<<<<<<< - * v = ctypes.c_int() - * self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_AddTraceback("epanet.epanet.Output.version", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_v); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":59 - * - * - * def net_size(self) -> dict[str, int]: # <<<<<<<<<<<<<< - * element_count = ctypes.POINTER(ctypes.c_int)() - * length = ctypes.c_int() -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_9net_size(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_9net_size = {"net_size", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_9net_size, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_9net_size(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("net_size (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 59, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 59, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "net_size", 0) < 0) __PYX_ERR(0, 59, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("net_size", 1, 1, 1, i); __PYX_ERR(0, 59, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 59, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("net_size", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 59, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.net_size", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_8net_size(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_8net_size(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_element_count = NULL; - PyObject *__pyx_v_length = NULL; - PyObject *__pyx_v_category = NULL; - PyObject *__pyx_v_sizes = NULL; - PyObject *__pyx_v_i = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - size_t __pyx_t_8; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - int __pyx_t_13; - Py_ssize_t __pyx_t_14; - PyObject *(*__pyx_t_15)(PyObject *); - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("net_size", 0); - - /* "epanet/epanet.py":60 - * - * def net_size(self) -> dict[str, int]: - * element_count = ctypes.POINTER(ctypes.c_int)() # <<<<<<<<<<<<<< - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNetSize(self._handle, ctypes.byref(element_count), ctypes.byref(length))) -*/ - __pyx_t_2 = NULL; - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_POINTER); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_7}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_8, (1-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_element_count = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":61 - * def net_size(self) -> dict[str, int]: - * element_count = ctypes.POINTER(ctypes.c_int)() - * length = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getNetSize(self._handle, ctypes.byref(element_count), ctypes.byref(length))) - * assert length.value == 5 -*/ - __pyx_t_3 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 61, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 61, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_3); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_8, (1-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 61, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_length = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":62 - * element_count = ctypes.POINTER(ctypes.c_int)() - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNetSize(self._handle, ctypes.byref(element_count), ctypes.byref(length))) # <<<<<<<<<<<<<< - * assert length.value == 5 - * category = ['node', 'tank', 'link', 'pump', 'valve'] -*/ - __pyx_t_6 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_2 = __pyx_t_7; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_v_element_count}; - __pyx_t_5 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - } - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_12 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_12))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_12); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_12); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_12, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_v_length}; - __pyx_t_11 = __Pyx_PyObject_FastCall(__pyx_t_12, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[4] = {__pyx_t_2, __pyx_t_4, __pyx_t_5, __pyx_t_11}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getNetSize, __pyx_callargs+__pyx_t_8, (4-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":63 - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNetSize(self._handle, ctypes.byref(element_count), ctypes.byref(length))) - * assert length.value == 5 # <<<<<<<<<<<<<< - * category = ['node', 'tank', 'link', 'pump', 'valve'] - * sizes = {} -*/ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(__pyx_assertions_enabled())) { - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 63, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_13 = (__Pyx_PyLong_BoolEqObjC(__pyx_t_1, __pyx_mstate_global->__pyx_int_5, 5, 0)); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 63, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_13)) { - __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); - __PYX_ERR(0, 63, __pyx_L1_error) - } - } - #else - if ((1)); else __PYX_ERR(0, 63, __pyx_L1_error) - #endif - - /* "epanet/epanet.py":64 - * self._check(self._lib.ENR_getNetSize(self._handle, ctypes.byref(element_count), ctypes.byref(length))) - * assert length.value == 5 - * category = ['node', 'tank', 'link', 'pump', 'valve'] # <<<<<<<<<<<<<< - * sizes = {} - * for i in range(length.value): -*/ - __pyx_t_1 = PyList_New(5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 64, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_node); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_node); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_mstate_global->__pyx_n_u_node) != (0)) __PYX_ERR(0, 64, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_tank); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_tank); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_mstate_global->__pyx_n_u_tank) != (0)) __PYX_ERR(0, 64, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_link); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_link); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 2, __pyx_mstate_global->__pyx_n_u_link) != (0)) __PYX_ERR(0, 64, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_pump); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_pump); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 3, __pyx_mstate_global->__pyx_n_u_pump) != (0)) __PYX_ERR(0, 64, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_valve); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_valve); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 4, __pyx_mstate_global->__pyx_n_u_valve) != (0)) __PYX_ERR(0, 64, __pyx_L1_error); - __pyx_v_category = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":65 - * assert length.value == 5 - * category = ['node', 'tank', 'link', 'pump', 'valve'] - * sizes = {} # <<<<<<<<<<<<<< - * for i in range(length.value): - * sizes[category[i]] = element_count[i] -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 65, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_sizes = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":66 - * category = ['node', 'tank', 'link', 'pump', 'valve'] - * sizes = {} - * for i in range(length.value): # <<<<<<<<<<<<<< - * sizes[category[i]] = element_count[i] - * self._lib.ENR_free(ctypes.byref(element_count)) -*/ - __pyx_t_3 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_6 = __pyx_builtin_range; - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 66, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_8 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_t_7}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 66, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { - __pyx_t_6 = __pyx_t_1; __Pyx_INCREF(__pyx_t_6); - __pyx_t_14 = 0; - __pyx_t_15 = NULL; - } else { - __pyx_t_14 = -1; __pyx_t_6 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 66, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_15 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_6); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 66, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - for (;;) { - if (likely(!__pyx_t_15)) { - if (likely(PyList_CheckExact(__pyx_t_6))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_6); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 66, __pyx_L1_error) - #endif - if (__pyx_t_14 >= __pyx_temp) break; - } - __pyx_t_1 = __Pyx_PyList_GetItemRef(__pyx_t_6, __pyx_t_14); - ++__pyx_t_14; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_6); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 66, __pyx_L1_error) - #endif - if (__pyx_t_14 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_6, __pyx_t_14)); - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_6, __pyx_t_14); - #endif - ++__pyx_t_14; - } - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 66, __pyx_L1_error) - } else { - __pyx_t_1 = __pyx_t_15(__pyx_t_6); - if (unlikely(!__pyx_t_1)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 66, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_1); - __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":67 - * sizes = {} - * for i in range(length.value): - * sizes[category[i]] = element_count[i] # <<<<<<<<<<<<<< - * self._lib.ENR_free(ctypes.byref(element_count)) - * return sizes -*/ - __pyx_t_1 = __Pyx_PyObject_GetItem(__pyx_v_element_count, __pyx_v_i); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 67, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_7 = __Pyx_PyObject_GetItem(__pyx_v_category, __pyx_v_i); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 67, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - if (unlikely((PyDict_SetItem(__pyx_v_sizes, __pyx_t_7, __pyx_t_1) < 0))) __PYX_ERR(0, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":66 - * category = ['node', 'tank', 'link', 'pump', 'valve'] - * sizes = {} - * for i in range(length.value): # <<<<<<<<<<<<<< - * sizes[category[i]] = element_count[i] - * self._lib.ENR_free(ctypes.byref(element_count)) -*/ - } - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "epanet/epanet.py":68 - * for i in range(length.value): - * sizes[category[i]] = element_count[i] - * self._lib.ENR_free(ctypes.byref(element_count)) # <<<<<<<<<<<<<< - * return sizes - * -*/ - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 68, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_1 = __pyx_t_7; - __Pyx_INCREF(__pyx_t_1); - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 68, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 68, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_element_count}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 68, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, __pyx_t_3}; - __pyx_t_6 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 68, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "epanet/epanet.py":69 - * sizes[category[i]] = element_count[i] - * self._lib.ENR_free(ctypes.byref(element_count)) - * return sizes # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_sizes); - __pyx_r = __pyx_v_sizes; - goto __pyx_L0; - - /* "epanet/epanet.py":59 - * - * - * def net_size(self) -> dict[str, int]: # <<<<<<<<<<<<<< - * element_count = ctypes.POINTER(ctypes.c_int)() - * length = ctypes.c_int() -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_AddTraceback("epanet.epanet.Output.net_size", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_element_count); - __Pyx_XDECREF(__pyx_v_length); - __Pyx_XDECREF(__pyx_v_category); - __Pyx_XDECREF(__pyx_v_sizes); - __Pyx_XDECREF(__pyx_v_i); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":72 - * - * - * def units(self) -> dict[str, str]: # <<<<<<<<<<<<<< - * f_us = ['CFS', 'GPM', 'MGD', 'IMGD', 'AFD', 'LPS', 'LPM', 'MLD', 'CMH', 'CMD'] - * p_us = ['PSI', 'MTR', 'KPA'] -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_11units(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_11units = {"units", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_11units, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_11units(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("units (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 72, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 72, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "units", 0) < 0) __PYX_ERR(0, 72, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("units", 1, 1, 1, i); __PYX_ERR(0, 72, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 72, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("units", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 72, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.units", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_10units(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_10units(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_f_us = NULL; - PyObject *__pyx_v_p_us = NULL; - PyObject *__pyx_v_q_us = NULL; - PyObject *__pyx_v_f = NULL; - PyObject *__pyx_v_p = NULL; - PyObject *__pyx_v_q = NULL; - PyObject *__pyx_v_f_u = NULL; - PyObject *__pyx_v_p_u = NULL; - PyObject *__pyx_v_q_u = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - size_t __pyx_t_5; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("units", 0); - - /* "epanet/epanet.py":73 - * - * def units(self) -> dict[str, str]: - * f_us = ['CFS', 'GPM', 'MGD', 'IMGD', 'AFD', 'LPS', 'LPM', 'MLD', 'CMH', 'CMD'] # <<<<<<<<<<<<<< - * p_us = ['PSI', 'MTR', 'KPA'] - * q_us = ['NONE', 'MGL', 'UGL', 'HOURS', 'PRCNT'] -*/ - __pyx_t_1 = PyList_New(10); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 73, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_CFS); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_CFS); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_mstate_global->__pyx_n_u_CFS) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_GPM); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_GPM); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_mstate_global->__pyx_n_u_GPM) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_MGD); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_MGD); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 2, __pyx_mstate_global->__pyx_n_u_MGD) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_IMGD); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_IMGD); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 3, __pyx_mstate_global->__pyx_n_u_IMGD) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_AFD); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_AFD); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 4, __pyx_mstate_global->__pyx_n_u_AFD) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_LPS); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_LPS); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 5, __pyx_mstate_global->__pyx_n_u_LPS) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_LPM); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_LPM); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 6, __pyx_mstate_global->__pyx_n_u_LPM) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_MLD); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_MLD); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 7, __pyx_mstate_global->__pyx_n_u_MLD) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_CMH); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_CMH); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 8, __pyx_mstate_global->__pyx_n_u_CMH) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_CMD); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_CMD); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 9, __pyx_mstate_global->__pyx_n_u_CMD) != (0)) __PYX_ERR(0, 73, __pyx_L1_error); - __pyx_v_f_us = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":74 - * def units(self) -> dict[str, str]: - * f_us = ['CFS', 'GPM', 'MGD', 'IMGD', 'AFD', 'LPS', 'LPM', 'MLD', 'CMH', 'CMD'] - * p_us = ['PSI', 'MTR', 'KPA'] # <<<<<<<<<<<<<< - * q_us = ['NONE', 'MGL', 'UGL', 'HOURS', 'PRCNT'] - * f, p, q = ctypes.c_int(1), ctypes.c_int(2), ctypes.c_int(3) -*/ - __pyx_t_1 = PyList_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 74, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_PSI); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_PSI); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_mstate_global->__pyx_n_u_PSI) != (0)) __PYX_ERR(0, 74, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_MTR); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_MTR); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_mstate_global->__pyx_n_u_MTR) != (0)) __PYX_ERR(0, 74, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_KPA); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_KPA); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 2, __pyx_mstate_global->__pyx_n_u_KPA) != (0)) __PYX_ERR(0, 74, __pyx_L1_error); - __pyx_v_p_us = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":75 - * f_us = ['CFS', 'GPM', 'MGD', 'IMGD', 'AFD', 'LPS', 'LPM', 'MLD', 'CMH', 'CMD'] - * p_us = ['PSI', 'MTR', 'KPA'] - * q_us = ['NONE', 'MGL', 'UGL', 'HOURS', 'PRCNT'] # <<<<<<<<<<<<<< - * f, p, q = ctypes.c_int(1), ctypes.c_int(2), ctypes.c_int(3) - * f_u, p_u, q_u = ctypes.c_int(), ctypes.c_int(), ctypes.c_int() -*/ - __pyx_t_1 = PyList_New(5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 75, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_NONE); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_NONE); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_mstate_global->__pyx_n_u_NONE) != (0)) __PYX_ERR(0, 75, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_MGL); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_MGL); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_mstate_global->__pyx_n_u_MGL) != (0)) __PYX_ERR(0, 75, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_UGL); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_UGL); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 2, __pyx_mstate_global->__pyx_n_u_UGL) != (0)) __PYX_ERR(0, 75, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_HOURS); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_HOURS); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 3, __pyx_mstate_global->__pyx_n_u_HOURS) != (0)) __PYX_ERR(0, 75, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_PRCNT); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_PRCNT); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 4, __pyx_mstate_global->__pyx_n_u_PRCNT) != (0)) __PYX_ERR(0, 75, __pyx_L1_error); - __pyx_v_q_us = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":76 - * p_us = ['PSI', 'MTR', 'KPA'] - * q_us = ['NONE', 'MGL', 'UGL', 'HOURS', 'PRCNT'] - * f, p, q = ctypes.c_int(1), ctypes.c_int(2), ctypes.c_int(3) # <<<<<<<<<<<<<< - * f_u, p_u, q_u = ctypes.c_int(), ctypes.c_int(), ctypes.c_int() - * self._check(self._lib.ENR_getUnits(self._handle, f, ctypes.byref(f_u))) -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_mstate_global->__pyx_int_1}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_mstate_global->__pyx_int_2}; - __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_7))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_7); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_7); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_7, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_mstate_global->__pyx_int_3}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_v_f = __pyx_t_1; - __pyx_t_1 = 0; - __pyx_v_p = __pyx_t_4; - __pyx_t_4 = 0; - __pyx_v_q = __pyx_t_6; - __pyx_t_6 = 0; - - /* "epanet/epanet.py":77 - * q_us = ['NONE', 'MGL', 'UGL', 'HOURS', 'PRCNT'] - * f, p, q = ctypes.c_int(1), ctypes.c_int(2), ctypes.c_int(3) - * f_u, p_u, q_u = ctypes.c_int(), ctypes.c_int(), ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getUnits(self._handle, f, ctypes.byref(f_u))) - * self._check(self._lib.ENR_getUnits(self._handle, p, ctypes.byref(p_u))) -*/ - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_7))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_7); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_7); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_7, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+__pyx_t_5, (1-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_2))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_2); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_2, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_7 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_5, (1-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - } - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_5, (1-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_v_f_u = __pyx_t_6; - __pyx_t_6 = 0; - __pyx_v_p_u = __pyx_t_7; - __pyx_t_7 = 0; - __pyx_v_q_u = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":78 - * f, p, q = ctypes.c_int(1), ctypes.c_int(2), ctypes.c_int(3) - * f_u, p_u, q_u = ctypes.c_int(), ctypes.c_int(), ctypes.c_int() - * self._check(self._lib.ENR_getUnits(self._handle, f, ctypes.byref(f_u))) # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getUnits(self._handle, p, ctypes.byref(p_u))) - * self._check(self._lib.ENR_getUnits(self._handle, q, ctypes.byref(q_u))) -*/ - __pyx_t_7 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_7); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_3 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_v_f_u}; - __pyx_t_8 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[4] = {__pyx_t_3, __pyx_t_1, __pyx_v_f, __pyx_t_8}; - __pyx_t_6 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getUnits, __pyx_callargs+__pyx_t_5, (4-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_t_6}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":79 - * f_u, p_u, q_u = ctypes.c_int(), ctypes.c_int(), ctypes.c_int() - * self._check(self._lib.ENR_getUnits(self._handle, f, ctypes.byref(f_u))) - * self._check(self._lib.ENR_getUnits(self._handle, p, ctypes.byref(p_u))) # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getUnits(self._handle, q, ctypes.byref(q_u))) - * return { 'flow': f_us[f_u.value], 'pressure': p_us[p_u.value], 'quality': q_us[q_u.value] } -*/ - __pyx_t_6 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_6); - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_4 = __pyx_t_8; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_10))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_10); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_10); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_10, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_p_u}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[4] = {__pyx_t_4, __pyx_t_1, __pyx_v_p, __pyx_t_3}; - __pyx_t_7 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getUnits, __pyx_callargs+__pyx_t_5, (4-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_t_7}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":80 - * self._check(self._lib.ENR_getUnits(self._handle, f, ctypes.byref(f_u))) - * self._check(self._lib.ENR_getUnits(self._handle, p, ctypes.byref(p_u))) - * self._check(self._lib.ENR_getUnits(self._handle, q, ctypes.byref(q_u))) # <<<<<<<<<<<<<< - * return { 'flow': f_us[f_u.value], 'pressure': p_us[p_u.value], 'quality': q_us[q_u.value] } - * -*/ - __pyx_t_7 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_7); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_8 = __pyx_t_3; - __Pyx_INCREF(__pyx_t_8); - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_9))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_9); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_v_q_u}; - __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[4] = {__pyx_t_8, __pyx_t_1, __pyx_v_q, __pyx_t_4}; - __pyx_t_6 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getUnits, __pyx_callargs+__pyx_t_5, (4-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_t_6}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":81 - * self._check(self._lib.ENR_getUnits(self._handle, p, ctypes.byref(p_u))) - * self._check(self._lib.ENR_getUnits(self._handle, q, ctypes.byref(q_u))) - * return { 'flow': f_us[f_u.value], 'pressure': p_us[p_u.value], 'quality': q_us[q_u.value] } # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_f_u, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetItem(__pyx_v_f_us, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_flow, __pyx_t_7) < 0) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_p_u, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_6 = __Pyx_PyObject_GetItem(__pyx_v_p_us, __pyx_t_7); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_pressure, __pyx_t_6) < 0) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_q_u, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetItem(__pyx_v_q_us, __pyx_t_6); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_quality, __pyx_t_7) < 0) __PYX_ERR(0, 81, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_r = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - goto __pyx_L0; - - /* "epanet/epanet.py":72 - * - * - * def units(self) -> dict[str, str]: # <<<<<<<<<<<<<< - * f_us = ['CFS', 'GPM', 'MGD', 'IMGD', 'AFD', 'LPS', 'LPM', 'MLD', 'CMH', 'CMD'] - * p_us = ['PSI', 'MTR', 'KPA'] -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_AddTraceback("epanet.epanet.Output.units", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_f_us); - __Pyx_XDECREF(__pyx_v_p_us); - __Pyx_XDECREF(__pyx_v_q_us); - __Pyx_XDECREF(__pyx_v_f); - __Pyx_XDECREF(__pyx_v_p); - __Pyx_XDECREF(__pyx_v_q); - __Pyx_XDECREF(__pyx_v_f_u); - __Pyx_XDECREF(__pyx_v_p_u); - __Pyx_XDECREF(__pyx_v_q_u); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":84 - * - * - * def times(self) -> dict[str, int]: # <<<<<<<<<<<<<< - * ts = [] - * for i in range(1, 5): -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_13times(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_13times = {"times", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_13times, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_13times(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("times (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 84, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 84, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "times", 0) < 0) __PYX_ERR(0, 84, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("times", 1, 1, 1, i); __PYX_ERR(0, 84, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 84, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("times", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 84, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.times", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_12times(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_12times(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_ts = NULL; - long __pyx_v_i; - PyObject *__pyx_v_t = NULL; - PyObject *__pyx_v_d = NULL; - PyObject *__pyx_v_category = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - long __pyx_t_2; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - size_t __pyx_t_6; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - int __pyx_t_14; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("times", 0); - - /* "epanet/epanet.py":85 - * - * def times(self) -> dict[str, int]: - * ts = [] # <<<<<<<<<<<<<< - * for i in range(1, 5): - * t = ctypes.c_int(1) -*/ - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 85, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_ts = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":86 - * def times(self) -> dict[str, int]: - * ts = [] - * for i in range(1, 5): # <<<<<<<<<<<<<< - * t = ctypes.c_int(1) - * self._check(self._lib.ENR_getTimes(self._handle, ctypes.c_int(i), ctypes.byref(t))) -*/ - for (__pyx_t_2 = 1; __pyx_t_2 < 5; __pyx_t_2+=1) { - __pyx_v_i = __pyx_t_2; - - /* "epanet/epanet.py":87 - * ts = [] - * for i in range(1, 5): - * t = ctypes.c_int(1) # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getTimes(self._handle, ctypes.c_int(i), ctypes.byref(t))) - * ts.append(t.value) -*/ - __pyx_t_3 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 87, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 87, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_6 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_3); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_6 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_mstate_global->__pyx_int_1}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_6, (2-__pyx_t_6) | (__pyx_t_6*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 87, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_XDECREF_SET(__pyx_v_t, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":88 - * for i in range(1, 5): - * t = ctypes.c_int(1) - * self._check(self._lib.ENR_getTimes(self._handle, ctypes.c_int(i), ctypes.byref(t))) # <<<<<<<<<<<<<< - * ts.append(t.value) - * d = {} -*/ - __pyx_t_5 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_5); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_4 = __pyx_t_7; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_12 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_11 = __Pyx_PyLong_From_long(__pyx_v_i); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_6 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_12))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_12); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_12); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_12, __pyx__function); - __pyx_t_6 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_t_11}; - __pyx_t_9 = __Pyx_PyObject_FastCall(__pyx_t_12, __pyx_callargs+__pyx_t_6, (2-__pyx_t_6) | (__pyx_t_6*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - } - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_6 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_13))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_13); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_13); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_13, __pyx__function); - __pyx_t_6 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_t}; - __pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_13, __pyx_callargs+__pyx_t_6, (2-__pyx_t_6) | (__pyx_t_6*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - } - __pyx_t_6 = 0; - { - PyObject *__pyx_callargs[4] = {__pyx_t_4, __pyx_t_8, __pyx_t_9, __pyx_t_12}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getTimes, __pyx_callargs+__pyx_t_6, (4-__pyx_t_6) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_6 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_6, (2-__pyx_t_6) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":89 - * t = ctypes.c_int(1) - * self._check(self._lib.ENR_getTimes(self._handle, ctypes.c_int(i), ctypes.byref(t))) - * ts.append(t.value) # <<<<<<<<<<<<<< - * d = {} - * category = ['report_start', 'report_step', 'sim_duration', 'num_periods'] -*/ - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_t, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 89, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_14 = __Pyx_PyList_Append(__pyx_v_ts, __pyx_t_1); if (unlikely(__pyx_t_14 == ((int)-1))) __PYX_ERR(0, 89, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } - - /* "epanet/epanet.py":90 - * self._check(self._lib.ENR_getTimes(self._handle, ctypes.c_int(i), ctypes.byref(t))) - * ts.append(t.value) - * d = {} # <<<<<<<<<<<<<< - * category = ['report_start', 'report_step', 'sim_duration', 'num_periods'] - * for i in range(4): -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 90, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_d = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":91 - * ts.append(t.value) - * d = {} - * category = ['report_start', 'report_step', 'sim_duration', 'num_periods'] # <<<<<<<<<<<<<< - * for i in range(4): - * d[category[i]] = ts[i] -*/ - __pyx_t_1 = PyList_New(4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 91, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_report_start); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_report_start); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_mstate_global->__pyx_n_u_report_start) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_report_step); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_report_step); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_mstate_global->__pyx_n_u_report_step) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_sim_duration); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_sim_duration); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 2, __pyx_mstate_global->__pyx_n_u_sim_duration) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_num_periods); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_num_periods); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 3, __pyx_mstate_global->__pyx_n_u_num_periods) != (0)) __PYX_ERR(0, 91, __pyx_L1_error); - __pyx_v_category = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":92 - * d = {} - * category = ['report_start', 'report_step', 'sim_duration', 'num_periods'] - * for i in range(4): # <<<<<<<<<<<<<< - * d[category[i]] = ts[i] - * return d -*/ - for (__pyx_t_2 = 0; __pyx_t_2 < 4; __pyx_t_2+=1) { - __pyx_v_i = __pyx_t_2; - - /* "epanet/epanet.py":93 - * category = ['report_start', 'report_step', 'sim_duration', 'num_periods'] - * for i in range(4): - * d[category[i]] = ts[i] # <<<<<<<<<<<<<< - * return d - * -*/ - __pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v_ts, __pyx_v_i, long, 1, __Pyx_PyLong_From_long, 1, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 93, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_GetItemInt_List(__pyx_v_category, __pyx_v_i, long, 1, __Pyx_PyLong_From_long, 1, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 93, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (unlikely((PyDict_SetItem(__pyx_v_d, __pyx_t_3, __pyx_t_1) < 0))) __PYX_ERR(0, 93, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } - - /* "epanet/epanet.py":94 - * for i in range(4): - * d[category[i]] = ts[i] - * return d # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_d); - __pyx_r = __pyx_v_d; - goto __pyx_L0; - - /* "epanet/epanet.py":84 - * - * - * def times(self) -> dict[str, int]: # <<<<<<<<<<<<<< - * ts = [] - * for i in range(1, 5): -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_XDECREF(__pyx_t_13); - __Pyx_AddTraceback("epanet.epanet.Output.times", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_ts); - __Pyx_XDECREF(__pyx_v_t); - __Pyx_XDECREF(__pyx_v_d); - __Pyx_XDECREF(__pyx_v_category); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":97 - * - * - * def element_name(self) -> dict[str, list[str]]: # <<<<<<<<<<<<<< - * sizes = self.net_size() - * -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_15element_name(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_15element_name = {"element_name", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_15element_name, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_15element_name(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("element_name (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 97, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 97, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "element_name", 0) < 0) __PYX_ERR(0, 97, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("element_name", 1, 1, 1, i); __PYX_ERR(0, 97, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 97, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("element_name", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 97, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.element_name", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_14element_name(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_14element_name(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_sizes = NULL; - PyObject *__pyx_v_node_type = NULL; - PyObject *__pyx_v_nodes = NULL; - PyObject *__pyx_v_i = NULL; - PyObject *__pyx_v_name = NULL; - PyObject *__pyx_v_name_len = NULL; - PyObject *__pyx_v_link_type = NULL; - PyObject *__pyx_v_links = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - size_t __pyx_t_3; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - Py_ssize_t __pyx_t_7; - PyObject *(*__pyx_t_8)(PyObject *); - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - PyObject *__pyx_t_14 = NULL; - PyObject *__pyx_t_15 = NULL; - PyObject *__pyx_t_16 = NULL; - int __pyx_t_17; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("element_name", 0); - - /* "epanet/epanet.py":98 - * - * def element_name(self) -> dict[str, list[str]]: - * sizes = self.net_size() # <<<<<<<<<<<<<< - * - * node_type = ctypes.c_int(1) -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_net_size, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 98, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_sizes = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":100 - * sizes = self.net_size() - * - * node_type = ctypes.c_int(1) # <<<<<<<<<<<<<< - * nodes = [] - * for i in range(1, sizes['node'] + 1): -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 100, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 100, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_mstate_global->__pyx_int_1}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 100, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_node_type = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":101 - * - * node_type = ctypes.c_int(1) - * nodes = [] # <<<<<<<<<<<<<< - * for i in range(1, sizes['node'] + 1): - * name = ctypes.c_char_p() -*/ - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 101, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_nodes = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":102 - * node_type = ctypes.c_int(1) - * nodes = [] - * for i in range(1, sizes['node'] + 1): # <<<<<<<<<<<<<< - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() -*/ - __pyx_t_5 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_2 = __pyx_builtin_range; - __pyx_t_4 = __Pyx_PyObject_Dict_GetItem(__pyx_v_sizes, __pyx_mstate_global->__pyx_n_u_node); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 102, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_6 = __Pyx_PyLong_AddObjC(__pyx_t_4, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 102, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_5, __pyx_mstate_global->__pyx_int_1, __pyx_t_6}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_3, (3-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 102, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { - __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); - __pyx_t_7 = 0; - __pyx_t_8 = NULL; - } else { - __pyx_t_7 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 102, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_8 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 102, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - for (;;) { - if (likely(!__pyx_t_8)) { - if (likely(PyList_CheckExact(__pyx_t_2))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 102, __pyx_L1_error) - #endif - if (__pyx_t_7 >= __pyx_temp) break; - } - __pyx_t_1 = __Pyx_PyList_GetItemRef(__pyx_t_2, __pyx_t_7); - ++__pyx_t_7; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 102, __pyx_L1_error) - #endif - if (__pyx_t_7 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_7)); - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_7); - #endif - ++__pyx_t_7; - } - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 102, __pyx_L1_error) - } else { - __pyx_t_1 = __pyx_t_8(__pyx_t_2); - if (unlikely(!__pyx_t_1)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 102, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_1); - __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":103 - * nodes = [] - * for i in range(1, sizes['node'] + 1): - * name = ctypes.c_char_p() # <<<<<<<<<<<<<< - * name_len = ctypes.c_int() - * self._check(self._lib.ENR_getElementName(self._handle, node_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) -*/ - __pyx_t_6 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 103, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_c_char_p); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 103, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_6 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_6); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_6); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_6, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 103, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_XDECREF_SET(__pyx_v_name, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":104 - * for i in range(1, sizes['node'] + 1): - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getElementName(self._handle, node_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - * nodes.append(name.value.decode()) -*/ - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 104, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 104, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 104, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_XDECREF_SET(__pyx_v_name_len, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":105 - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() - * self._check(self._lib.ENR_getElementName(self._handle, node_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) # <<<<<<<<<<<<<< - * nodes.append(name.value.decode()) - * self._lib.ENR_free(ctypes.byref(name)) -*/ - __pyx_t_5 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_5); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_6 = __pyx_t_9; - __Pyx_INCREF(__pyx_t_6); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_14))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_14); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_14); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_14, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_i}; - __pyx_t_11 = __Pyx_PyObject_FastCall(__pyx_t_14, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - } - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_15); - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_15))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_15); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_15); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_15, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_name}; - __pyx_t_14 = __Pyx_PyObject_FastCall(__pyx_t_15, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; - if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - } - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_16))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_16); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_16); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_16, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_name_len}; - __pyx_t_15 = __Pyx_PyObject_FastCall(__pyx_t_16, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_15); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[6] = {__pyx_t_6, __pyx_t_10, __pyx_v_node_type, __pyx_t_11, __pyx_t_14, __pyx_t_15}; - __pyx_t_4 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getElementName, __pyx_callargs+__pyx_t_3, (6-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_4}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 105, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":106 - * name_len = ctypes.c_int() - * self._check(self._lib.ENR_getElementName(self._handle, node_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - * nodes.append(name.value.decode()) # <<<<<<<<<<<<<< - * self._lib.ENR_free(ctypes.byref(name)) - * -*/ - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_name, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 106, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = __pyx_t_5; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_decode, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 106, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_17 = __Pyx_PyList_Append(__pyx_v_nodes, __pyx_t_1); if (unlikely(__pyx_t_17 == ((int)-1))) __PYX_ERR(0, 106, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":107 - * self._check(self._lib.ENR_getElementName(self._handle, node_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - * nodes.append(name.value.decode()) - * self._lib.ENR_free(ctypes.byref(name)) # <<<<<<<<<<<<<< - * - * link_type = ctypes.c_int(2) -*/ - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 107, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_5); - __pyx_t_15 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_14, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 107, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_14, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 107, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_15 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_15); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_15); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_15, __pyx_v_name}; - __pyx_t_9 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 107, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_9}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 107, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":102 - * node_type = ctypes.c_int(1) - * nodes = [] - * for i in range(1, sizes['node'] + 1): # <<<<<<<<<<<<<< - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() -*/ - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":109 - * self._lib.ENR_free(ctypes.byref(name)) - * - * link_type = ctypes.c_int(2) # <<<<<<<<<<<<<< - * links = [] - * for i in range(1, sizes['link'] + 1): -*/ - __pyx_t_1 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 109, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 109, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_9))) { - __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_9); - assert(__pyx_t_1); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); - __Pyx_INCREF(__pyx_t_1); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, __pyx_mstate_global->__pyx_int_2}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 109, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_v_link_type = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":110 - * - * link_type = ctypes.c_int(2) - * links = [] # <<<<<<<<<<<<<< - * for i in range(1, sizes['link'] + 1): - * name = ctypes.c_char_p() -*/ - __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 110, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_v_links = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":111 - * link_type = ctypes.c_int(2) - * links = [] - * for i in range(1, sizes['link'] + 1): # <<<<<<<<<<<<<< - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() -*/ - __pyx_t_9 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_1 = __pyx_builtin_range; - __pyx_t_4 = __Pyx_PyObject_Dict_GetItem(__pyx_v_sizes, __pyx_mstate_global->__pyx_n_u_link); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 111, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = __Pyx_PyLong_AddObjC(__pyx_t_4, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 111, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_9, __pyx_mstate_global->__pyx_int_1, __pyx_t_5}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+__pyx_t_3, (3-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 111, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { - __pyx_t_1 = __pyx_t_2; __Pyx_INCREF(__pyx_t_1); - __pyx_t_7 = 0; - __pyx_t_8 = NULL; - } else { - __pyx_t_7 = -1; __pyx_t_1 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 111, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_8 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_1); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 111, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - for (;;) { - if (likely(!__pyx_t_8)) { - if (likely(PyList_CheckExact(__pyx_t_1))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 111, __pyx_L1_error) - #endif - if (__pyx_t_7 >= __pyx_temp) break; - } - __pyx_t_2 = __Pyx_PyList_GetItemRef(__pyx_t_1, __pyx_t_7); - ++__pyx_t_7; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_1); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 111, __pyx_L1_error) - #endif - if (__pyx_t_7 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_2 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_1, __pyx_t_7)); - #else - __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_1, __pyx_t_7); - #endif - ++__pyx_t_7; - } - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 111, __pyx_L1_error) - } else { - __pyx_t_2 = __pyx_t_8(__pyx_t_1); - if (unlikely(!__pyx_t_2)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 111, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_2); - __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":112 - * links = [] - * for i in range(1, sizes['link'] + 1): - * name = ctypes.c_char_p() # <<<<<<<<<<<<<< - * name_len = ctypes.c_int() - * self._check(self._lib.ENR_getElementName(self._handle, link_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) -*/ - __pyx_t_5 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 112, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_c_char_p); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 112, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 112, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_XDECREF_SET(__pyx_v_name, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":113 - * for i in range(1, sizes['link'] + 1): - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getElementName(self._handle, link_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - * links.append(name.value.decode()) -*/ - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 113, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 113, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_9))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_9); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_XDECREF_SET(__pyx_v_name_len, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":114 - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() - * self._check(self._lib.ENR_getElementName(self._handle, link_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) # <<<<<<<<<<<<<< - * links.append(name.value.decode()) - * self._lib.ENR_free(ctypes.byref(name)) -*/ - __pyx_t_9 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_9); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_5 = __pyx_t_11; - __Pyx_INCREF(__pyx_t_5); - __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_15); - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_16))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_16); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_16); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_16, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_v_i}; - __pyx_t_14 = __Pyx_PyObject_FastCall(__pyx_t_16, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - } - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_12 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_12))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_12); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_12); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_12, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_v_name}; - __pyx_t_16 = __Pyx_PyObject_FastCall(__pyx_t_12, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - } - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_13))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_13); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_13); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_13, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_v_name_len}; - __pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_13, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[6] = {__pyx_t_5, __pyx_t_15, __pyx_v_link_type, __pyx_t_14, __pyx_t_16, __pyx_t_12}; - __pyx_t_4 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getElementName, __pyx_callargs+__pyx_t_3, (6-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_t_4}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 114, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":115 - * name_len = ctypes.c_int() - * self._check(self._lib.ENR_getElementName(self._handle, link_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - * links.append(name.value.decode()) # <<<<<<<<<<<<<< - * self._lib.ENR_free(ctypes.byref(name)) - * -*/ - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_v_name, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 115, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_4 = __pyx_t_9; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_decode, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 115, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_17 = __Pyx_PyList_Append(__pyx_v_links, __pyx_t_2); if (unlikely(__pyx_t_17 == ((int)-1))) __PYX_ERR(0, 115, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":116 - * self._check(self._lib.ENR_getElementName(self._handle, link_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - * links.append(name.value.decode()) - * self._lib.ENR_free(ctypes.byref(name)) # <<<<<<<<<<<<<< - * - * return { 'nodes' : nodes, 'links': links } -*/ - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 116, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_9 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_9); - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 116, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 116, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_14))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_14); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_14); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_14, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_name}; - __pyx_t_11 = __Pyx_PyObject_FastCall(__pyx_t_14, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 116, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_t_11}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 116, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":111 - * link_type = ctypes.c_int(2) - * links = [] - * for i in range(1, sizes['link'] + 1): # <<<<<<<<<<<<<< - * name = ctypes.c_char_p() - * name_len = ctypes.c_int() -*/ - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":118 - * self._lib.ENR_free(ctypes.byref(name)) - * - * return { 'nodes' : nodes, 'links': links } # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 118, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_nodes, __pyx_v_nodes) < 0) __PYX_ERR(0, 118, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_links, __pyx_v_links) < 0) __PYX_ERR(0, 118, __pyx_L1_error) - __pyx_r = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "epanet/epanet.py":97 - * - * - * def element_name(self) -> dict[str, list[str]]: # <<<<<<<<<<<<<< - * sizes = self.net_size() - * -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_XDECREF(__pyx_t_13); - __Pyx_XDECREF(__pyx_t_14); - __Pyx_XDECREF(__pyx_t_15); - __Pyx_XDECREF(__pyx_t_16); - __Pyx_AddTraceback("epanet.epanet.Output.element_name", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_sizes); - __Pyx_XDECREF(__pyx_v_node_type); - __Pyx_XDECREF(__pyx_v_nodes); - __Pyx_XDECREF(__pyx_v_i); - __Pyx_XDECREF(__pyx_v_name); - __Pyx_XDECREF(__pyx_v_name_len); - __Pyx_XDECREF(__pyx_v_link_type); - __Pyx_XDECREF(__pyx_v_links); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":121 - * - * - * def energy_usage(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['pump'] - * usages = [] -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_17energy_usage(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_17energy_usage = {"energy_usage", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_17energy_usage, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_17energy_usage(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("energy_usage (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 121, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 121, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "energy_usage", 0) < 0) __PYX_ERR(0, 121, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("energy_usage", 1, 1, 1, i); __PYX_ERR(0, 121, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 121, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("energy_usage", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 121, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.energy_usage", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_16energy_usage(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_16energy_usage(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_size = NULL; - PyObject *__pyx_v_usages = NULL; - PyObject *__pyx_v_category = NULL; - PyObject *__pyx_v_links = NULL; - PyObject *__pyx_v_i = NULL; - PyObject *__pyx_v_index = NULL; - PyObject *__pyx_v_values = NULL; - PyObject *__pyx_v_length = NULL; - PyObject *__pyx_v_d = NULL; - PyObject *__pyx_v_j = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - size_t __pyx_t_3; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - Py_ssize_t __pyx_t_6; - PyObject *(*__pyx_t_7)(PyObject *); - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - PyObject *__pyx_t_14 = NULL; - PyObject *__pyx_t_15 = NULL; - PyObject *__pyx_t_16 = NULL; - PyObject *__pyx_t_17 = NULL; - int __pyx_t_18; - Py_ssize_t __pyx_t_19; - PyObject *(*__pyx_t_20)(PyObject *); - int __pyx_t_21; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("energy_usage", 0); - - /* "epanet/epanet.py":122 - * - * def energy_usage(self) -> list[dict[str, Any]]: - * size = self.net_size()['pump'] # <<<<<<<<<<<<<< - * usages = [] - * category = ['utilization', 'avg.efficiency', 'avg.kW/flow', 'avg.kwatts', 'max.kwatts', 'cost/day' ] -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_net_size, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 122, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_pump); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 122, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_size = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":123 - * def energy_usage(self) -> list[dict[str, Any]]: - * size = self.net_size()['pump'] - * usages = [] # <<<<<<<<<<<<<< - * category = ['utilization', 'avg.efficiency', 'avg.kW/flow', 'avg.kwatts', 'max.kwatts', 'cost/day' ] - * links = self.element_name()['links'] -*/ - __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 123, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_v_usages = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":124 - * size = self.net_size()['pump'] - * usages = [] - * category = ['utilization', 'avg.efficiency', 'avg.kW/flow', 'avg.kwatts', 'max.kwatts', 'cost/day' ] # <<<<<<<<<<<<<< - * links = self.element_name()['links'] - * for i in range(1, size + 1): -*/ - __pyx_t_2 = PyList_New(6); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 124, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_utilization); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_utilization); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_mstate_global->__pyx_n_u_utilization) != (0)) __PYX_ERR(0, 124, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_kp_u_avg_efficiency); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_kp_u_avg_efficiency); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_mstate_global->__pyx_kp_u_avg_efficiency) != (0)) __PYX_ERR(0, 124, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_kp_u_avg_kW_flow); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_kp_u_avg_kW_flow); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_mstate_global->__pyx_kp_u_avg_kW_flow) != (0)) __PYX_ERR(0, 124, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_kp_u_avg_kwatts); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_kp_u_avg_kwatts); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_mstate_global->__pyx_kp_u_avg_kwatts) != (0)) __PYX_ERR(0, 124, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_kp_u_max_kwatts); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_kp_u_max_kwatts); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 4, __pyx_mstate_global->__pyx_kp_u_max_kwatts) != (0)) __PYX_ERR(0, 124, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_kp_u_cost_day); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_kp_u_cost_day); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 5, __pyx_mstate_global->__pyx_kp_u_cost_day) != (0)) __PYX_ERR(0, 124, __pyx_L1_error); - __pyx_v_category = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":125 - * usages = [] - * category = ['utilization', 'avg.efficiency', 'avg.kW/flow', 'avg.kwatts', 'max.kwatts', 'cost/day' ] - * links = self.element_name()['links'] # <<<<<<<<<<<<<< - * for i in range(1, size + 1): - * index = ctypes.c_int() -*/ - __pyx_t_1 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_1); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_element_name, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 125, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_1 = __Pyx_PyObject_Dict_GetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_links); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 125, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_v_links = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":126 - * category = ['utilization', 'avg.efficiency', 'avg.kW/flow', 'avg.kwatts', 'max.kwatts', 'cost/day' ] - * links = self.element_name()['links'] - * for i in range(1, size + 1): # <<<<<<<<<<<<<< - * index = ctypes.c_int() - * values = ctypes.POINTER(ctypes.c_float)() -*/ - __pyx_t_2 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_4 = __pyx_builtin_range; - __pyx_t_5 = __Pyx_PyLong_AddObjC(__pyx_v_size, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 126, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_2, __pyx_mstate_global->__pyx_int_1, __pyx_t_5}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_3, (3-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { - __pyx_t_4 = __pyx_t_1; __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = 0; - __pyx_t_7 = NULL; - } else { - __pyx_t_6 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 126, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_7 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 126, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - for (;;) { - if (likely(!__pyx_t_7)) { - if (likely(PyList_CheckExact(__pyx_t_4))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_4); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 126, __pyx_L1_error) - #endif - if (__pyx_t_6 >= __pyx_temp) break; - } - __pyx_t_1 = __Pyx_PyList_GetItemRef(__pyx_t_4, __pyx_t_6); - ++__pyx_t_6; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_4); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 126, __pyx_L1_error) - #endif - if (__pyx_t_6 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_6)); - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_6); - #endif - ++__pyx_t_6; - } - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 126, __pyx_L1_error) - } else { - __pyx_t_1 = __pyx_t_7(__pyx_t_4); - if (unlikely(!__pyx_t_1)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 126, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_1); - __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":127 - * links = self.element_name()['links'] - * for i in range(1, size + 1): - * index = ctypes.c_int() # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - __pyx_t_5 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 127, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_8 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 127, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_8))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_8); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_8); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_8, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_8, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 127, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_XDECREF_SET(__pyx_v_index, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":128 - * for i in range(1, size + 1): - * index = ctypes.c_int() - * values = ctypes.POINTER(ctypes.c_float)() # <<<<<<<<<<<<<< - * length = ctypes.c_int() - * self._check(self._lib.ENR_getEnergyUsage(self._handle, ctypes.c_int(i), ctypes.byref(index), ctypes.byref(values), ctypes.byref(length))) -*/ - __pyx_t_8 = NULL; - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 128, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_POINTER); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 128, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 128, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_c_float); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 128, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_10))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_10); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_10); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_10, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_t_11}; - __pyx_t_5 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 128, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - } - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_8 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_8); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_8); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_8, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 128, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_XDECREF_SET(__pyx_v_values, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":129 - * index = ctypes.c_int() - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getEnergyUsage(self._handle, ctypes.c_int(i), ctypes.byref(index), ctypes.byref(values), ctypes.byref(length))) - * assert length.value == 6 -*/ - __pyx_t_5 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_8, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 129, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_8); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_8, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 129, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_10))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_10); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_10); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_10, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 129, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":130 - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() - * self._check(self._lib.ENR_getEnergyUsage(self._handle, ctypes.c_int(i), ctypes.byref(index), ctypes.byref(values), ctypes.byref(length))) # <<<<<<<<<<<<<< - * assert length.value == 6 - * d = { 'pump' : links[index.value - 1] } -*/ - __pyx_t_10 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_8 = __pyx_t_11; - __Pyx_INCREF(__pyx_t_8); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_14))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_14); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_14); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_14, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_i}; - __pyx_t_9 = __Pyx_PyObject_FastCall(__pyx_t_14, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - } - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_15 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_15); - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_15))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_15); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_15); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_15, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_index}; - __pyx_t_14 = __Pyx_PyObject_FastCall(__pyx_t_15, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; - if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - } - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_16 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_16))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_16); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_16); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_16, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_values}; - __pyx_t_15 = __Pyx_PyObject_FastCall(__pyx_t_16, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_15); - } - __pyx_t_12 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_17 = __Pyx_PyObject_GetAttrStr(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_17); - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_17))) { - __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_17); - assert(__pyx_t_12); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_17); - __Pyx_INCREF(__pyx_t_12); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_17, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_12, __pyx_v_length}; - __pyx_t_16 = __Pyx_PyObject_FastCall(__pyx_t_17, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; - if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[6] = {__pyx_t_8, __pyx_t_2, __pyx_t_9, __pyx_t_14, __pyx_t_15, __pyx_t_16}; - __pyx_t_5 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getEnergyUsage, __pyx_callargs+__pyx_t_3, (6-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_t_5}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 130, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":131 - * length = ctypes.c_int() - * self._check(self._lib.ENR_getEnergyUsage(self._handle, ctypes.c_int(i), ctypes.byref(index), ctypes.byref(values), ctypes.byref(length))) - * assert length.value == 6 # <<<<<<<<<<<<<< - * d = { 'pump' : links[index.value - 1] } - * for j in range(length.value): -*/ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(__pyx_assertions_enabled())) { - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 131, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_18 = (__Pyx_PyLong_BoolEqObjC(__pyx_t_1, __pyx_mstate_global->__pyx_int_6, 6, 0)); if (unlikely((__pyx_t_18 < 0))) __PYX_ERR(0, 131, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_18)) { - __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); - __PYX_ERR(0, 131, __pyx_L1_error) - } - } - #else - if ((1)); else __PYX_ERR(0, 131, __pyx_L1_error) - #endif - - /* "epanet/epanet.py":132 - * self._check(self._lib.ENR_getEnergyUsage(self._handle, ctypes.c_int(i), ctypes.byref(index), ctypes.byref(values), ctypes.byref(length))) - * assert length.value == 6 - * d = { 'pump' : links[index.value - 1] } # <<<<<<<<<<<<<< - * for j in range(length.value): - * d |= { category[j] : values[j] } -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 132, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_v_index, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 132, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_10 = __Pyx_PyLong_SubtractObjC(__pyx_t_5, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 132, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_5 = __Pyx_PyObject_GetItem(__pyx_v_links, __pyx_t_10); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 132, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_pump, __pyx_t_5) < 0) __PYX_ERR(0, 132, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_XDECREF_SET(__pyx_v_d, ((PyObject*)__pyx_t_1)); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":133 - * assert length.value == 6 - * d = { 'pump' : links[index.value - 1] } - * for j in range(length.value): # <<<<<<<<<<<<<< - * d |= { category[j] : values[j] } - * usages.append(d) -*/ - __pyx_t_5 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_10 = __pyx_builtin_range; - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 133, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_11}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 133, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (likely(PyList_CheckExact(__pyx_t_1)) || PyTuple_CheckExact(__pyx_t_1)) { - __pyx_t_10 = __pyx_t_1; __Pyx_INCREF(__pyx_t_10); - __pyx_t_19 = 0; - __pyx_t_20 = NULL; - } else { - __pyx_t_19 = -1; __pyx_t_10 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 133, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_20 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_10); if (unlikely(!__pyx_t_20)) __PYX_ERR(0, 133, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - for (;;) { - if (likely(!__pyx_t_20)) { - if (likely(PyList_CheckExact(__pyx_t_10))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_10); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 133, __pyx_L1_error) - #endif - if (__pyx_t_19 >= __pyx_temp) break; - } - __pyx_t_1 = __Pyx_PyList_GetItemRef(__pyx_t_10, __pyx_t_19); - ++__pyx_t_19; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_10); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 133, __pyx_L1_error) - #endif - if (__pyx_t_19 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_1 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_10, __pyx_t_19)); - #else - __pyx_t_1 = __Pyx_PySequence_ITEM(__pyx_t_10, __pyx_t_19); - #endif - ++__pyx_t_19; - } - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 133, __pyx_L1_error) - } else { - __pyx_t_1 = __pyx_t_20(__pyx_t_10); - if (unlikely(!__pyx_t_1)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 133, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_1); - __Pyx_XDECREF_SET(__pyx_v_j, __pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":134 - * d = { 'pump' : links[index.value - 1] } - * for j in range(length.value): - * d |= { category[j] : values[j] } # <<<<<<<<<<<<<< - * usages.append(d) - * self._lib.ENR_free(ctypes.byref(values)) -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 134, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_11 = __Pyx_PyObject_GetItem(__pyx_v_category, __pyx_v_j); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 134, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_5 = __Pyx_PyObject_GetItem(__pyx_v_values, __pyx_v_j); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 134, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - if (PyDict_SetItem(__pyx_t_1, __pyx_t_11, __pyx_t_5) < 0) __PYX_ERR(0, 134, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_5 = PyNumber_InPlaceOr(__pyx_v_d, __pyx_t_1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 134, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF_SET(__pyx_v_d, ((PyObject*)__pyx_t_5)); - __pyx_t_5 = 0; - - /* "epanet/epanet.py":133 - * assert length.value == 6 - * d = { 'pump' : links[index.value - 1] } - * for j in range(length.value): # <<<<<<<<<<<<<< - * d |= { category[j] : values[j] } - * usages.append(d) -*/ - } - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - - /* "epanet/epanet.py":135 - * for j in range(length.value): - * d |= { category[j] : values[j] } - * usages.append(d) # <<<<<<<<<<<<<< - * self._lib.ENR_free(ctypes.byref(values)) - * return usages -*/ - __pyx_t_21 = __Pyx_PyList_Append(__pyx_v_usages, __pyx_v_d); if (unlikely(__pyx_t_21 == ((int)-1))) __PYX_ERR(0, 135, __pyx_L1_error) - - /* "epanet/epanet.py":136 - * d |= { category[j] : values[j] } - * usages.append(d) - * self._lib.ENR_free(ctypes.byref(values)) # <<<<<<<<<<<<<< - * return usages - * -*/ - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 136, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_5 = __pyx_t_1; - __Pyx_INCREF(__pyx_t_5); - __pyx_t_16 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_15, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 136, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_15); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_15, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 136, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_14))) { - __pyx_t_16 = PyMethod_GET_SELF(__pyx_t_14); - assert(__pyx_t_16); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_14); - __Pyx_INCREF(__pyx_t_16); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_14, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_16, __pyx_v_values}; - __pyx_t_11 = __Pyx_PyObject_FastCall(__pyx_t_14, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_16); __pyx_t_16 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 136, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_t_11}; - __pyx_t_10 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 136, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - } - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - - /* "epanet/epanet.py":126 - * category = ['utilization', 'avg.efficiency', 'avg.kW/flow', 'avg.kwatts', 'max.kwatts', 'cost/day' ] - * links = self.element_name()['links'] - * for i in range(1, size + 1): # <<<<<<<<<<<<<< - * index = ctypes.c_int() - * values = ctypes.POINTER(ctypes.c_float)() -*/ - } - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "epanet/epanet.py":137 - * usages.append(d) - * self._lib.ENR_free(ctypes.byref(values)) - * return usages # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_usages); - __pyx_r = __pyx_v_usages; - goto __pyx_L0; - - /* "epanet/epanet.py":121 - * - * - * def energy_usage(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['pump'] - * usages = [] -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_8); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_XDECREF(__pyx_t_13); - __Pyx_XDECREF(__pyx_t_14); - __Pyx_XDECREF(__pyx_t_15); - __Pyx_XDECREF(__pyx_t_16); - __Pyx_XDECREF(__pyx_t_17); - __Pyx_AddTraceback("epanet.epanet.Output.energy_usage", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_size); - __Pyx_XDECREF(__pyx_v_usages); - __Pyx_XDECREF(__pyx_v_category); - __Pyx_XDECREF(__pyx_v_links); - __Pyx_XDECREF(__pyx_v_i); - __Pyx_XDECREF(__pyx_v_index); - __Pyx_XDECREF(__pyx_v_values); - __Pyx_XDECREF(__pyx_v_length); - __Pyx_XDECREF(__pyx_v_d); - __Pyx_XDECREF(__pyx_v_j); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":140 - * - * - * def reactions(self) -> dict[str, float]: # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_19reactions(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_19reactions = {"reactions", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_19reactions, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_19reactions(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("reactions (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 140, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 140, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "reactions", 0) < 0) __PYX_ERR(0, 140, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("reactions", 1, 1, 1, i); __PYX_ERR(0, 140, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 140, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("reactions", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 140, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.reactions", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_18reactions(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_18reactions(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_values = NULL; - PyObject *__pyx_v_length = NULL; - PyObject *__pyx_v_category = NULL; - PyObject *__pyx_v_d = NULL; - long __pyx_v_i; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - size_t __pyx_t_8; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - int __pyx_t_13; - long __pyx_t_14; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("reactions", 0); - - /* "epanet/epanet.py":141 - * - * def reactions(self) -> dict[str, float]: - * values = ctypes.POINTER(ctypes.c_float)() # <<<<<<<<<<<<<< - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNetReacts(self._handle, ctypes.byref(values), ctypes.byref(length))) -*/ - __pyx_t_2 = NULL; - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 141, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_POINTER); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 141, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 141, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_c_float); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 141, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_7}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 141, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_8, (1-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 141, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_values = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":142 - * def reactions(self) -> dict[str, float]: - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getNetReacts(self._handle, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == 4 -*/ - __pyx_t_3 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 142, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 142, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_3); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_8, (1-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 142, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_length = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":143 - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNetReacts(self._handle, ctypes.byref(values), ctypes.byref(length))) # <<<<<<<<<<<<<< - * assert length.value == 4 - * category = ['bulk', 'wall', 'tank', 'source'] -*/ - __pyx_t_6 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_2 = __pyx_t_7; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_v_values}; - __pyx_t_5 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - } - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_12 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_12))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_12); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_12); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_12, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_v_length}; - __pyx_t_11 = __Pyx_PyObject_FastCall(__pyx_t_12, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[4] = {__pyx_t_2, __pyx_t_4, __pyx_t_5, __pyx_t_11}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getNetReacts, __pyx_callargs+__pyx_t_8, (4-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 143, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":144 - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNetReacts(self._handle, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == 4 # <<<<<<<<<<<<<< - * category = ['bulk', 'wall', 'tank', 'source'] - * d = {} -*/ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(__pyx_assertions_enabled())) { - __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 144, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_13 = (__Pyx_PyLong_BoolEqObjC(__pyx_t_1, __pyx_mstate_global->__pyx_int_4, 4, 0)); if (unlikely((__pyx_t_13 < 0))) __PYX_ERR(0, 144, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_13)) { - __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); - __PYX_ERR(0, 144, __pyx_L1_error) - } - } - #else - if ((1)); else __PYX_ERR(0, 144, __pyx_L1_error) - #endif - - /* "epanet/epanet.py":145 - * self._check(self._lib.ENR_getNetReacts(self._handle, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == 4 - * category = ['bulk', 'wall', 'tank', 'source'] # <<<<<<<<<<<<<< - * d = {} - * for i in range(4): -*/ - __pyx_t_1 = PyList_New(4); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 145, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_bulk); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_bulk); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 0, __pyx_mstate_global->__pyx_n_u_bulk) != (0)) __PYX_ERR(0, 145, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_wall); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_wall); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 1, __pyx_mstate_global->__pyx_n_u_wall) != (0)) __PYX_ERR(0, 145, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_tank); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_tank); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 2, __pyx_mstate_global->__pyx_n_u_tank) != (0)) __PYX_ERR(0, 145, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_source); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_source); - if (__Pyx_PyList_SET_ITEM(__pyx_t_1, 3, __pyx_mstate_global->__pyx_n_u_source) != (0)) __PYX_ERR(0, 145, __pyx_L1_error); - __pyx_v_category = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":146 - * assert length.value == 4 - * category = ['bulk', 'wall', 'tank', 'source'] - * d = {} # <<<<<<<<<<<<<< - * for i in range(4): - * d[category[i]] = values[i] -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 146, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_d = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":147 - * category = ['bulk', 'wall', 'tank', 'source'] - * d = {} - * for i in range(4): # <<<<<<<<<<<<<< - * d[category[i]] = values[i] - * self._lib.ENR_free(ctypes.byref(values)) -*/ - for (__pyx_t_14 = 0; __pyx_t_14 < 4; __pyx_t_14+=1) { - __pyx_v_i = __pyx_t_14; - - /* "epanet/epanet.py":148 - * d = {} - * for i in range(4): - * d[category[i]] = values[i] # <<<<<<<<<<<<<< - * self._lib.ENR_free(ctypes.byref(values)) - * return d -*/ - __pyx_t_1 = __Pyx_GetItemInt(__pyx_v_values, __pyx_v_i, long, 1, __Pyx_PyLong_From_long, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 148, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __Pyx_GetItemInt_List(__pyx_v_category, __pyx_v_i, long, 1, __Pyx_PyLong_From_long, 1, 1, 1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 148, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (unlikely((PyDict_SetItem(__pyx_v_d, __pyx_t_3, __pyx_t_1) < 0))) __PYX_ERR(0, 148, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - } - - /* "epanet/epanet.py":149 - * for i in range(4): - * d[category[i]] = values[i] - * self._lib.ENR_free(ctypes.byref(values)) # <<<<<<<<<<<<<< - * return d - * -*/ - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 149, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_3 = __pyx_t_6; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 149, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 149, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_values}; - __pyx_t_7 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 149, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_t_7}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 149, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":150 - * d[category[i]] = values[i] - * self._lib.ENR_free(ctypes.byref(values)) - * return d # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_d); - __pyx_r = __pyx_v_d; - goto __pyx_L0; - - /* "epanet/epanet.py":140 - * - * - * def reactions(self) -> dict[str, float]: # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_AddTraceback("epanet.epanet.Output.reactions", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_values); - __Pyx_XDECREF(__pyx_v_length); - __Pyx_XDECREF(__pyx_v_category); - __Pyx_XDECREF(__pyx_v_d); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":153 - * - * - * def node_results(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['node'] - * num_periods = self.times()['num_periods'] -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_21node_results(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_21node_results = {"node_results", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_21node_results, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_21node_results(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("node_results (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 153, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 153, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "node_results", 0) < 0) __PYX_ERR(0, 153, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("node_results", 1, 1, 1, i); __PYX_ERR(0, 153, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 153, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("node_results", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 153, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.node_results", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_20node_results(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_20node_results(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_size = NULL; - PyObject *__pyx_v_num_periods = NULL; - PyObject *__pyx_v_nodes = NULL; - PyObject *__pyx_v_category = NULL; - PyObject *__pyx_v_ds = NULL; - PyObject *__pyx_v_i = NULL; - PyObject *__pyx_v_d = NULL; - PyObject *__pyx_v_j = NULL; - PyObject *__pyx_v_values = NULL; - PyObject *__pyx_v_length = NULL; - PyObject *__pyx_v_attributes = NULL; - PyObject *__pyx_v_k = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - size_t __pyx_t_3; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - Py_ssize_t __pyx_t_6; - PyObject *(*__pyx_t_7)(PyObject *); - Py_ssize_t __pyx_t_8; - PyObject *(*__pyx_t_9)(PyObject *); - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - PyObject *__pyx_t_14 = NULL; - PyObject *__pyx_t_15 = NULL; - PyObject *__pyx_t_16 = NULL; - PyObject *__pyx_t_17 = NULL; - PyObject *__pyx_t_18 = NULL; - Py_ssize_t __pyx_t_19; - int __pyx_t_20; - PyObject *(*__pyx_t_21)(PyObject *); - int __pyx_t_22; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("node_results", 0); - - /* "epanet/epanet.py":154 - * - * def node_results(self) -> list[dict[str, Any]]: - * size = self.net_size()['node'] # <<<<<<<<<<<<<< - * num_periods = self.times()['num_periods'] - * nodes = self.element_name()['nodes'] -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_net_size, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 154, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_node); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 154, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_size = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":155 - * def node_results(self) -> list[dict[str, Any]]: - * size = self.net_size()['node'] - * num_periods = self.times()['num_periods'] # <<<<<<<<<<<<<< - * nodes = self.element_name()['nodes'] - * category = ['demand', 'head', 'pressure', 'quality'] -*/ - __pyx_t_1 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_1); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_times, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 155, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_1 = __Pyx_PyObject_Dict_GetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_num_periods); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 155, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_v_num_periods = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":156 - * size = self.net_size()['node'] - * num_periods = self.times()['num_periods'] - * nodes = self.element_name()['nodes'] # <<<<<<<<<<<<<< - * category = ['demand', 'head', 'pressure', 'quality'] - * ds = [] -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_element_name, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 156, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_nodes); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 156, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_nodes = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":157 - * num_periods = self.times()['num_periods'] - * nodes = self.element_name()['nodes'] - * category = ['demand', 'head', 'pressure', 'quality'] # <<<<<<<<<<<<<< - * ds = [] - * for i in range(1, size + 1): -*/ - __pyx_t_2 = PyList_New(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 157, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_demand); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_demand); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_mstate_global->__pyx_n_u_demand) != (0)) __PYX_ERR(0, 157, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_head); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_head); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_mstate_global->__pyx_n_u_head) != (0)) __PYX_ERR(0, 157, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_pressure); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_pressure); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_mstate_global->__pyx_n_u_pressure) != (0)) __PYX_ERR(0, 157, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_quality); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_quality); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_mstate_global->__pyx_n_u_quality) != (0)) __PYX_ERR(0, 157, __pyx_L1_error); - __pyx_v_category = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":158 - * nodes = self.element_name()['nodes'] - * category = ['demand', 'head', 'pressure', 'quality'] - * ds = [] # <<<<<<<<<<<<<< - * for i in range(1, size + 1): - * d = { 'node' : nodes[i - 1], 'result' : [] } -*/ - __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 158, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_v_ds = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":159 - * category = ['demand', 'head', 'pressure', 'quality'] - * ds = [] - * for i in range(1, size + 1): # <<<<<<<<<<<<<< - * d = { 'node' : nodes[i - 1], 'result' : [] } - * for j in range(num_periods): -*/ - __pyx_t_1 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_4 = __pyx_builtin_range; - __pyx_t_5 = __Pyx_PyLong_AddObjC(__pyx_v_size, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 159, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_1, __pyx_mstate_global->__pyx_int_1, __pyx_t_5}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_3, (3-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 159, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { - __pyx_t_4 = __pyx_t_2; __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = 0; - __pyx_t_7 = NULL; - } else { - __pyx_t_6 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 159, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_7 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 159, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - for (;;) { - if (likely(!__pyx_t_7)) { - if (likely(PyList_CheckExact(__pyx_t_4))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_4); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 159, __pyx_L1_error) - #endif - if (__pyx_t_6 >= __pyx_temp) break; - } - __pyx_t_2 = __Pyx_PyList_GetItemRef(__pyx_t_4, __pyx_t_6); - ++__pyx_t_6; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_4); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 159, __pyx_L1_error) - #endif - if (__pyx_t_6 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_2 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_6)); - #else - __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_6); - #endif - ++__pyx_t_6; - } - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 159, __pyx_L1_error) - } else { - __pyx_t_2 = __pyx_t_7(__pyx_t_4); - if (unlikely(!__pyx_t_2)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 159, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_2); - __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":160 - * ds = [] - * for i in range(1, size + 1): - * d = { 'node' : nodes[i - 1], 'result' : [] } # <<<<<<<<<<<<<< - * for j in range(num_periods): - * values = ctypes.POINTER(ctypes.c_float)() -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 160, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_5 = __Pyx_PyLong_SubtractObjC(__pyx_v_i, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 160, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_1 = __Pyx_PyObject_GetItem(__pyx_v_nodes, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 160, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_node, __pyx_t_1) < 0) __PYX_ERR(0, 160, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 160, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_result, __pyx_t_1) < 0) __PYX_ERR(0, 160, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF_SET(__pyx_v_d, ((PyObject*)__pyx_t_2)); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":161 - * for i in range(1, size + 1): - * d = { 'node' : nodes[i - 1], 'result' : [] } - * for j in range(num_periods): # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - __pyx_t_1 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_5 = __pyx_builtin_range; - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, __pyx_v_num_periods}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 161, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { - __pyx_t_5 = __pyx_t_2; __Pyx_INCREF(__pyx_t_5); - __pyx_t_8 = 0; - __pyx_t_9 = NULL; - } else { - __pyx_t_8 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 161, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_9 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 161, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - for (;;) { - if (likely(!__pyx_t_9)) { - if (likely(PyList_CheckExact(__pyx_t_5))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 161, __pyx_L1_error) - #endif - if (__pyx_t_8 >= __pyx_temp) break; - } - __pyx_t_2 = __Pyx_PyList_GetItemRef(__pyx_t_5, __pyx_t_8); - ++__pyx_t_8; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 161, __pyx_L1_error) - #endif - if (__pyx_t_8 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_2 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_8)); - #else - __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_8); - #endif - ++__pyx_t_8; - } - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 161, __pyx_L1_error) - } else { - __pyx_t_2 = __pyx_t_9(__pyx_t_5); - if (unlikely(!__pyx_t_2)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 161, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_2); - __Pyx_XDECREF_SET(__pyx_v_j, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":162 - * d = { 'node' : nodes[i - 1], 'result' : [] } - * for j in range(num_periods): - * values = ctypes.POINTER(ctypes.c_float)() # <<<<<<<<<<<<<< - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNodeResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) -*/ - __pyx_t_1 = NULL; - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 162, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_POINTER); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 162, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 162, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_c_float); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 162, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_13))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_13); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_13); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_13, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_t_14}; - __pyx_t_10 = __Pyx_PyObject_FastCall(__pyx_t_13, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 162, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - } - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_10))) { - __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_10); - assert(__pyx_t_1); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_10); - __Pyx_INCREF(__pyx_t_1); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_10, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 162, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_XDECREF_SET(__pyx_v_values, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":163 - * for j in range(num_periods): - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getNodeResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == len(category) -*/ - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 163, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 163, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_13))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_13); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_13); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_13, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_13, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 163, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":164 - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNodeResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) # <<<<<<<<<<<<<< - * assert length.value == len(category) - * attributes = {} -*/ - __pyx_t_13 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_13); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __pyx_t_1 = __pyx_t_14; - __Pyx_INCREF(__pyx_t_1); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_15 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __pyx_t_17 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_17); - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_17))) { - __pyx_t_15 = PyMethod_GET_SELF(__pyx_t_17); - assert(__pyx_t_15); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_17); - __Pyx_INCREF(__pyx_t_15); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_17, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_15, __pyx_v_values}; - __pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_17, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; - if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - } - __pyx_t_15 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __pyx_t_18 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_18); - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_18))) { - __pyx_t_15 = PyMethod_GET_SELF(__pyx_t_18); - assert(__pyx_t_15); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_18); - __Pyx_INCREF(__pyx_t_15); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_18, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_15, __pyx_v_length}; - __pyx_t_17 = __Pyx_PyObject_FastCall(__pyx_t_18, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; - if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_17); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[6] = {__pyx_t_1, __pyx_t_11, __pyx_v_j, __pyx_v_i, __pyx_t_12, __pyx_t_17}; - __pyx_t_10 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getNodeResult, __pyx_callargs+__pyx_t_3, (6-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_13, __pyx_t_10}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 164, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":165 - * length = ctypes.c_int() - * self._check(self._lib.ENR_getNodeResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == len(category) # <<<<<<<<<<<<<< - * attributes = {} - * for k in range(length.value): -*/ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(__pyx_assertions_enabled())) { - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 165, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_19 = __Pyx_PyList_GET_SIZE(__pyx_v_category); if (unlikely(__pyx_t_19 == ((Py_ssize_t)-1))) __PYX_ERR(0, 165, __pyx_L1_error) - __pyx_t_10 = PyLong_FromSsize_t(__pyx_t_19); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 165, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_13 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_13); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 165, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_20 = __Pyx_PyObject_IsTrue(__pyx_t_13); if (unlikely((__pyx_t_20 < 0))) __PYX_ERR(0, 165, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_20)) { - __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); - __PYX_ERR(0, 165, __pyx_L1_error) - } - } - #else - if ((1)); else __PYX_ERR(0, 165, __pyx_L1_error) - #endif - - /* "epanet/epanet.py":166 - * self._check(self._lib.ENR_getNodeResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == len(category) - * attributes = {} # <<<<<<<<<<<<<< - * for k in range(length.value): - * attributes[category[k]] = values[k] -*/ - __pyx_t_13 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 166, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_XDECREF_SET(__pyx_v_attributes, ((PyObject*)__pyx_t_13)); - __pyx_t_13 = 0; - - /* "epanet/epanet.py":167 - * assert length.value == len(category) - * attributes = {} - * for k in range(length.value): # <<<<<<<<<<<<<< - * attributes[category[k]] = values[k] - * d['result'].append(attributes) -*/ - __pyx_t_10 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_2 = __pyx_builtin_range; - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 167, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_t_14}; - __pyx_t_13 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 167, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - } - if (likely(PyList_CheckExact(__pyx_t_13)) || PyTuple_CheckExact(__pyx_t_13)) { - __pyx_t_2 = __pyx_t_13; __Pyx_INCREF(__pyx_t_2); - __pyx_t_19 = 0; - __pyx_t_21 = NULL; - } else { - __pyx_t_19 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_13); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 167, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_21 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_21)) __PYX_ERR(0, 167, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - for (;;) { - if (likely(!__pyx_t_21)) { - if (likely(PyList_CheckExact(__pyx_t_2))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 167, __pyx_L1_error) - #endif - if (__pyx_t_19 >= __pyx_temp) break; - } - __pyx_t_13 = __Pyx_PyList_GetItemRef(__pyx_t_2, __pyx_t_19); - ++__pyx_t_19; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 167, __pyx_L1_error) - #endif - if (__pyx_t_19 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_13 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_19)); - #else - __pyx_t_13 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_19); - #endif - ++__pyx_t_19; - } - if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 167, __pyx_L1_error) - } else { - __pyx_t_13 = __pyx_t_21(__pyx_t_2); - if (unlikely(!__pyx_t_13)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 167, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_13); - __Pyx_XDECREF_SET(__pyx_v_k, __pyx_t_13); - __pyx_t_13 = 0; - - /* "epanet/epanet.py":168 - * attributes = {} - * for k in range(length.value): - * attributes[category[k]] = values[k] # <<<<<<<<<<<<<< - * d['result'].append(attributes) - * self._lib.ENR_free(ctypes.byref(values)) -*/ - __pyx_t_13 = __Pyx_PyObject_GetItem(__pyx_v_values, __pyx_v_k); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 168, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_14 = __Pyx_PyObject_GetItem(__pyx_v_category, __pyx_v_k); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 168, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - if (unlikely((PyDict_SetItem(__pyx_v_attributes, __pyx_t_14, __pyx_t_13) < 0))) __PYX_ERR(0, 168, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - - /* "epanet/epanet.py":167 - * assert length.value == len(category) - * attributes = {} - * for k in range(length.value): # <<<<<<<<<<<<<< - * attributes[category[k]] = values[k] - * d['result'].append(attributes) -*/ - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":169 - * for k in range(length.value): - * attributes[category[k]] = values[k] - * d['result'].append(attributes) # <<<<<<<<<<<<<< - * self._lib.ENR_free(ctypes.byref(values)) - * ds.append(d) -*/ - __pyx_t_2 = __Pyx_PyDict_GetItem(__pyx_v_d, __pyx_mstate_global->__pyx_n_u_result); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 169, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_22 = __Pyx_PyObject_Append(__pyx_t_2, __pyx_v_attributes); if (unlikely(__pyx_t_22 == ((int)-1))) __PYX_ERR(0, 169, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":170 - * attributes[category[k]] = values[k] - * d['result'].append(attributes) - * self._lib.ENR_free(ctypes.byref(values)) # <<<<<<<<<<<<<< - * ds.append(d) - * return ds -*/ - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 170, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __pyx_t_13 = __pyx_t_14; - __Pyx_INCREF(__pyx_t_13); - __pyx_t_17 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 170, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 170, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_17 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_17); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_17); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_17, __pyx_v_values}; - __pyx_t_10 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_17); __pyx_t_17 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 170, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_13, __pyx_t_10}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 170, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":161 - * for i in range(1, size + 1): - * d = { 'node' : nodes[i - 1], 'result' : [] } - * for j in range(num_periods): # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - } - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - - /* "epanet/epanet.py":171 - * d['result'].append(attributes) - * self._lib.ENR_free(ctypes.byref(values)) - * ds.append(d) # <<<<<<<<<<<<<< - * return ds - * -*/ - __pyx_t_22 = __Pyx_PyList_Append(__pyx_v_ds, __pyx_v_d); if (unlikely(__pyx_t_22 == ((int)-1))) __PYX_ERR(0, 171, __pyx_L1_error) - - /* "epanet/epanet.py":159 - * category = ['demand', 'head', 'pressure', 'quality'] - * ds = [] - * for i in range(1, size + 1): # <<<<<<<<<<<<<< - * d = { 'node' : nodes[i - 1], 'result' : [] } - * for j in range(num_periods): -*/ - } - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "epanet/epanet.py":172 - * self._lib.ENR_free(ctypes.byref(values)) - * ds.append(d) - * return ds # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_ds); - __pyx_r = __pyx_v_ds; - goto __pyx_L0; - - /* "epanet/epanet.py":153 - * - * - * def node_results(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['node'] - * num_periods = self.times()['num_periods'] -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_XDECREF(__pyx_t_13); - __Pyx_XDECREF(__pyx_t_14); - __Pyx_XDECREF(__pyx_t_15); - __Pyx_XDECREF(__pyx_t_16); - __Pyx_XDECREF(__pyx_t_17); - __Pyx_XDECREF(__pyx_t_18); - __Pyx_AddTraceback("epanet.epanet.Output.node_results", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_size); - __Pyx_XDECREF(__pyx_v_num_periods); - __Pyx_XDECREF(__pyx_v_nodes); - __Pyx_XDECREF(__pyx_v_category); - __Pyx_XDECREF(__pyx_v_ds); - __Pyx_XDECREF(__pyx_v_i); - __Pyx_XDECREF(__pyx_v_d); - __Pyx_XDECREF(__pyx_v_j); - __Pyx_XDECREF(__pyx_v_values); - __Pyx_XDECREF(__pyx_v_length); - __Pyx_XDECREF(__pyx_v_attributes); - __Pyx_XDECREF(__pyx_v_k); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":175 - * - * - * def link_results(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['link'] - * num_periods = self.times()['num_periods'] -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_23link_results(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_23link_results = {"link_results", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_23link_results, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_23link_results(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("link_results (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 175, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 175, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "link_results", 0) < 0) __PYX_ERR(0, 175, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("link_results", 1, 1, 1, i); __PYX_ERR(0, 175, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 175, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("link_results", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 175, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.link_results", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_22link_results(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_22link_results(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_size = NULL; - PyObject *__pyx_v_num_periods = NULL; - PyObject *__pyx_v_links = NULL; - PyObject *__pyx_v_category = NULL; - PyObject *__pyx_v_ds = NULL; - PyObject *__pyx_v_i = NULL; - PyObject *__pyx_v_d = NULL; - PyObject *__pyx_v_j = NULL; - PyObject *__pyx_v_values = NULL; - PyObject *__pyx_v_length = NULL; - PyObject *__pyx_v_attributes = NULL; - PyObject *__pyx_v_k = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - size_t __pyx_t_3; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - Py_ssize_t __pyx_t_6; - PyObject *(*__pyx_t_7)(PyObject *); - Py_ssize_t __pyx_t_8; - PyObject *(*__pyx_t_9)(PyObject *); - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12 = NULL; - PyObject *__pyx_t_13 = NULL; - PyObject *__pyx_t_14 = NULL; - PyObject *__pyx_t_15 = NULL; - PyObject *__pyx_t_16 = NULL; - PyObject *__pyx_t_17 = NULL; - PyObject *__pyx_t_18 = NULL; - Py_ssize_t __pyx_t_19; - int __pyx_t_20; - PyObject *(*__pyx_t_21)(PyObject *); - int __pyx_t_22; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("link_results", 0); - - /* "epanet/epanet.py":176 - * - * def link_results(self) -> list[dict[str, Any]]: - * size = self.net_size()['link'] # <<<<<<<<<<<<<< - * num_periods = self.times()['num_periods'] - * links = self.element_name()['links'] -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_net_size, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 176, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_link); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 176, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_size = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":177 - * def link_results(self) -> list[dict[str, Any]]: - * size = self.net_size()['link'] - * num_periods = self.times()['num_periods'] # <<<<<<<<<<<<<< - * links = self.element_name()['links'] - * category = ['flow', 'velocity', 'headloss', 'quality', 'status', 'setting', 'reaction', 'friction'] -*/ - __pyx_t_1 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_1); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_times, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 177, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_1 = __Pyx_PyObject_Dict_GetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_num_periods); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 177, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_v_num_periods = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":178 - * size = self.net_size()['link'] - * num_periods = self.times()['num_periods'] - * links = self.element_name()['links'] # <<<<<<<<<<<<<< - * category = ['flow', 'velocity', 'headloss', 'quality', 'status', 'setting', 'reaction', 'friction'] - * ds = [] -*/ - __pyx_t_2 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_element_name, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 178, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_2 = __Pyx_PyObject_Dict_GetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_links); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 178, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_v_links = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":179 - * num_periods = self.times()['num_periods'] - * links = self.element_name()['links'] - * category = ['flow', 'velocity', 'headloss', 'quality', 'status', 'setting', 'reaction', 'friction'] # <<<<<<<<<<<<<< - * ds = [] - * -*/ - __pyx_t_2 = PyList_New(8); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 179, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_flow); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_flow); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 0, __pyx_mstate_global->__pyx_n_u_flow) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_velocity); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_velocity); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 1, __pyx_mstate_global->__pyx_n_u_velocity) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_headloss); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_headloss); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 2, __pyx_mstate_global->__pyx_n_u_headloss) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_quality); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_quality); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 3, __pyx_mstate_global->__pyx_n_u_quality) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_status); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_status); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 4, __pyx_mstate_global->__pyx_n_u_status) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_setting); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_setting); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 5, __pyx_mstate_global->__pyx_n_u_setting) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_reaction); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_reaction); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 6, __pyx_mstate_global->__pyx_n_u_reaction) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_friction); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_n_u_friction); - if (__Pyx_PyList_SET_ITEM(__pyx_t_2, 7, __pyx_mstate_global->__pyx_n_u_friction) != (0)) __PYX_ERR(0, 179, __pyx_L1_error); - __pyx_v_category = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":180 - * links = self.element_name()['links'] - * category = ['flow', 'velocity', 'headloss', 'quality', 'status', 'setting', 'reaction', 'friction'] - * ds = [] # <<<<<<<<<<<<<< - * - * for i in range(1, size + 1): -*/ - __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 180, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_v_ds = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":182 - * ds = [] - * - * for i in range(1, size + 1): # <<<<<<<<<<<<<< - * d = { 'link' : links[i - 1], 'result' : [] } - * for j in range(num_periods): -*/ - __pyx_t_1 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_4 = __pyx_builtin_range; - __pyx_t_5 = __Pyx_PyLong_AddObjC(__pyx_v_size, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 182, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_1, __pyx_mstate_global->__pyx_int_1, __pyx_t_5}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_3, (3-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 182, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { - __pyx_t_4 = __pyx_t_2; __Pyx_INCREF(__pyx_t_4); - __pyx_t_6 = 0; - __pyx_t_7 = NULL; - } else { - __pyx_t_6 = -1; __pyx_t_4 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 182, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_7 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 182, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - for (;;) { - if (likely(!__pyx_t_7)) { - if (likely(PyList_CheckExact(__pyx_t_4))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_4); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 182, __pyx_L1_error) - #endif - if (__pyx_t_6 >= __pyx_temp) break; - } - __pyx_t_2 = __Pyx_PyList_GetItemRef(__pyx_t_4, __pyx_t_6); - ++__pyx_t_6; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_4); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 182, __pyx_L1_error) - #endif - if (__pyx_t_6 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_2 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_4, __pyx_t_6)); - #else - __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_4, __pyx_t_6); - #endif - ++__pyx_t_6; - } - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 182, __pyx_L1_error) - } else { - __pyx_t_2 = __pyx_t_7(__pyx_t_4); - if (unlikely(!__pyx_t_2)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 182, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_2); - __Pyx_XDECREF_SET(__pyx_v_i, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":183 - * - * for i in range(1, size + 1): - * d = { 'link' : links[i - 1], 'result' : [] } # <<<<<<<<<<<<<< - * for j in range(num_periods): - * values = ctypes.POINTER(ctypes.c_float)() -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 183, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_5 = __Pyx_PyLong_SubtractObjC(__pyx_v_i, __pyx_mstate_global->__pyx_int_1, 1, 0, 0); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 183, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_1 = __Pyx_PyObject_GetItem(__pyx_v_links, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 183, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_link, __pyx_t_1) < 0) __PYX_ERR(0, 183, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyList_New(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 183, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_result, __pyx_t_1) < 0) __PYX_ERR(0, 183, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF_SET(__pyx_v_d, ((PyObject*)__pyx_t_2)); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":184 - * for i in range(1, size + 1): - * d = { 'link' : links[i - 1], 'result' : [] } - * for j in range(num_periods): # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - __pyx_t_1 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_5 = __pyx_builtin_range; - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, __pyx_v_num_periods}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 184, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (likely(PyList_CheckExact(__pyx_t_2)) || PyTuple_CheckExact(__pyx_t_2)) { - __pyx_t_5 = __pyx_t_2; __Pyx_INCREF(__pyx_t_5); - __pyx_t_8 = 0; - __pyx_t_9 = NULL; - } else { - __pyx_t_8 = -1; __pyx_t_5 = PyObject_GetIter(__pyx_t_2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 184, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_9 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_5); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 184, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - for (;;) { - if (likely(!__pyx_t_9)) { - if (likely(PyList_CheckExact(__pyx_t_5))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 184, __pyx_L1_error) - #endif - if (__pyx_t_8 >= __pyx_temp) break; - } - __pyx_t_2 = __Pyx_PyList_GetItemRef(__pyx_t_5, __pyx_t_8); - ++__pyx_t_8; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_5); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 184, __pyx_L1_error) - #endif - if (__pyx_t_8 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_2 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_5, __pyx_t_8)); - #else - __pyx_t_2 = __Pyx_PySequence_ITEM(__pyx_t_5, __pyx_t_8); - #endif - ++__pyx_t_8; - } - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 184, __pyx_L1_error) - } else { - __pyx_t_2 = __pyx_t_9(__pyx_t_5); - if (unlikely(!__pyx_t_2)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 184, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_2); - __Pyx_XDECREF_SET(__pyx_v_j, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":185 - * d = { 'link' : links[i - 1], 'result' : [] } - * for j in range(num_periods): - * values = ctypes.POINTER(ctypes.c_float)() # <<<<<<<<<<<<<< - * length = ctypes.c_int() - * self._check(self._lib.ENR_getLinkResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) -*/ - __pyx_t_1 = NULL; - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 185, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_POINTER); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 185, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 185, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_c_float); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 185, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_13))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_13); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_13); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_13, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_t_14}; - __pyx_t_10 = __Pyx_PyObject_FastCall(__pyx_t_13, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 185, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - } - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_10))) { - __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_10); - assert(__pyx_t_1); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_10); - __Pyx_INCREF(__pyx_t_1); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_10, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_10, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 185, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_XDECREF_SET(__pyx_v_values, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":186 - * for j in range(num_periods): - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() # <<<<<<<<<<<<<< - * self._check(self._lib.ENR_getLinkResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == len(category) -*/ - __pyx_t_10 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 186, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_13 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_c_int); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 186, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_13))) { - __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_13); - assert(__pyx_t_10); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_13); - __Pyx_INCREF(__pyx_t_10); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_13, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_13, __pyx_callargs+__pyx_t_3, (1-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 186, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_XDECREF_SET(__pyx_v_length, __pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":187 - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() - * self._check(self._lib.ENR_getLinkResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) # <<<<<<<<<<<<<< - * assert length.value == len(category) - * attributes = {} -*/ - __pyx_t_13 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_13); - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __pyx_t_1 = __pyx_t_14; - __Pyx_INCREF(__pyx_t_1); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_handle); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_15 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __pyx_t_17 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_17); - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_17))) { - __pyx_t_15 = PyMethod_GET_SELF(__pyx_t_17); - assert(__pyx_t_15); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_17); - __Pyx_INCREF(__pyx_t_15); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_17, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_15, __pyx_v_values}; - __pyx_t_12 = __Pyx_PyObject_FastCall(__pyx_t_17, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; - if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - } - __pyx_t_15 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_16); - __pyx_t_18 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_18); - __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_18))) { - __pyx_t_15 = PyMethod_GET_SELF(__pyx_t_18); - assert(__pyx_t_15); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_18); - __Pyx_INCREF(__pyx_t_15); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_18, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_15, __pyx_v_length}; - __pyx_t_17 = __Pyx_PyObject_FastCall(__pyx_t_18, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_15); __pyx_t_15 = 0; - __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; - if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_17); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[6] = {__pyx_t_1, __pyx_t_11, __pyx_v_j, __pyx_v_i, __pyx_t_12, __pyx_t_17}; - __pyx_t_10 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_getLinkResult, __pyx_callargs+__pyx_t_3, (6-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_13, __pyx_t_10}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_check, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 187, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":188 - * length = ctypes.c_int() - * self._check(self._lib.ENR_getLinkResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == len(category) # <<<<<<<<<<<<<< - * attributes = {} - * for k in range(length.value): -*/ - #ifndef CYTHON_WITHOUT_ASSERTIONS - if (unlikely(__pyx_assertions_enabled())) { - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 188, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_19 = __Pyx_PyList_GET_SIZE(__pyx_v_category); if (unlikely(__pyx_t_19 == ((Py_ssize_t)-1))) __PYX_ERR(0, 188, __pyx_L1_error) - __pyx_t_10 = PyLong_FromSsize_t(__pyx_t_19); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 188, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_13 = PyObject_RichCompare(__pyx_t_2, __pyx_t_10, Py_EQ); __Pyx_XGOTREF(__pyx_t_13); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 188, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_20 = __Pyx_PyObject_IsTrue(__pyx_t_13); if (unlikely((__pyx_t_20 < 0))) __PYX_ERR(0, 188, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (unlikely(!__pyx_t_20)) { - __Pyx_Raise(__pyx_builtin_AssertionError, 0, 0, 0); - __PYX_ERR(0, 188, __pyx_L1_error) - } - } - #else - if ((1)); else __PYX_ERR(0, 188, __pyx_L1_error) - #endif - - /* "epanet/epanet.py":189 - * self._check(self._lib.ENR_getLinkResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - * assert length.value == len(category) - * attributes = {} # <<<<<<<<<<<<<< - * for k in range(length.value): - * if category[k] == 'status': -*/ - __pyx_t_13 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 189, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __Pyx_XDECREF_SET(__pyx_v_attributes, ((PyObject*)__pyx_t_13)); - __pyx_t_13 = 0; - - /* "epanet/epanet.py":190 - * assert length.value == len(category) - * attributes = {} - * for k in range(length.value): # <<<<<<<<<<<<<< - * if category[k] == 'status': - * if values[k] == 2.0: -*/ - __pyx_t_10 = NULL; - __Pyx_INCREF(__pyx_builtin_range); - __pyx_t_2 = __pyx_builtin_range; - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_length, __pyx_mstate_global->__pyx_n_u_value); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 190, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __pyx_t_3 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_10, __pyx_t_14}; - __pyx_t_13 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 190, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - } - if (likely(PyList_CheckExact(__pyx_t_13)) || PyTuple_CheckExact(__pyx_t_13)) { - __pyx_t_2 = __pyx_t_13; __Pyx_INCREF(__pyx_t_2); - __pyx_t_19 = 0; - __pyx_t_21 = NULL; - } else { - __pyx_t_19 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_13); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 190, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_21 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_21)) __PYX_ERR(0, 190, __pyx_L1_error) - } - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - for (;;) { - if (likely(!__pyx_t_21)) { - if (likely(PyList_CheckExact(__pyx_t_2))) { - { - Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 190, __pyx_L1_error) - #endif - if (__pyx_t_19 >= __pyx_temp) break; - } - __pyx_t_13 = __Pyx_PyList_GetItemRef(__pyx_t_2, __pyx_t_19); - ++__pyx_t_19; - } else { - { - Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 190, __pyx_L1_error) - #endif - if (__pyx_t_19 >= __pyx_temp) break; - } - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - __pyx_t_13 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_19)); - #else - __pyx_t_13 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_19); - #endif - ++__pyx_t_19; - } - if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 190, __pyx_L1_error) - } else { - __pyx_t_13 = __pyx_t_21(__pyx_t_2); - if (unlikely(!__pyx_t_13)) { - PyObject* exc_type = PyErr_Occurred(); - if (exc_type) { - if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 190, __pyx_L1_error) - PyErr_Clear(); - } - break; - } - } - __Pyx_GOTREF(__pyx_t_13); - __Pyx_XDECREF_SET(__pyx_v_k, __pyx_t_13); - __pyx_t_13 = 0; - - /* "epanet/epanet.py":191 - * attributes = {} - * for k in range(length.value): - * if category[k] == 'status': # <<<<<<<<<<<<<< - * if values[k] == 2.0: - * attributes[category[k]] = 'CLOSED' -*/ - __pyx_t_13 = __Pyx_PyObject_GetItem(__pyx_v_category, __pyx_v_k); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 191, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_20 = (__Pyx_PyUnicode_Equals(__pyx_t_13, __pyx_mstate_global->__pyx_n_u_status, Py_EQ)); if (unlikely((__pyx_t_20 < 0))) __PYX_ERR(0, 191, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (__pyx_t_20) { - - /* "epanet/epanet.py":192 - * for k in range(length.value): - * if category[k] == 'status': - * if values[k] == 2.0: # <<<<<<<<<<<<<< - * attributes[category[k]] = 'CLOSED' - * else: -*/ - __pyx_t_13 = __Pyx_PyObject_GetItem(__pyx_v_values, __pyx_v_k); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 192, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_20 = (__Pyx_PyFloat_BoolEqObjC(__pyx_t_13, __pyx_mstate_global->__pyx_float_2_0, 2.0, 0, 0)); if (unlikely((__pyx_t_20 < 0))) __PYX_ERR(0, 192, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - if (__pyx_t_20) { - - /* "epanet/epanet.py":193 - * if category[k] == 'status': - * if values[k] == 2.0: - * attributes[category[k]] = 'CLOSED' # <<<<<<<<<<<<<< - * else: - * attributes[category[k]] = 'OPEN' -*/ - __pyx_t_13 = __Pyx_PyObject_GetItem(__pyx_v_category, __pyx_v_k); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 193, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - if (unlikely((PyDict_SetItem(__pyx_v_attributes, __pyx_t_13, __pyx_mstate_global->__pyx_n_u_CLOSED) < 0))) __PYX_ERR(0, 193, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - - /* "epanet/epanet.py":192 - * for k in range(length.value): - * if category[k] == 'status': - * if values[k] == 2.0: # <<<<<<<<<<<<<< - * attributes[category[k]] = 'CLOSED' - * else: -*/ - goto __pyx_L10; - } - - /* "epanet/epanet.py":195 - * attributes[category[k]] = 'CLOSED' - * else: - * attributes[category[k]] = 'OPEN' # <<<<<<<<<<<<<< - * continue - * attributes[category[k]] = values[k] -*/ - /*else*/ { - __pyx_t_13 = __Pyx_PyObject_GetItem(__pyx_v_category, __pyx_v_k); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 195, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - if (unlikely((PyDict_SetItem(__pyx_v_attributes, __pyx_t_13, __pyx_mstate_global->__pyx_n_u_OPEN) < 0))) __PYX_ERR(0, 195, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - } - __pyx_L10:; - - /* "epanet/epanet.py":196 - * else: - * attributes[category[k]] = 'OPEN' - * continue # <<<<<<<<<<<<<< - * attributes[category[k]] = values[k] - * d['result'].append(attributes) -*/ - goto __pyx_L7_continue; - - /* "epanet/epanet.py":191 - * attributes = {} - * for k in range(length.value): - * if category[k] == 'status': # <<<<<<<<<<<<<< - * if values[k] == 2.0: - * attributes[category[k]] = 'CLOSED' -*/ - } - - /* "epanet/epanet.py":197 - * attributes[category[k]] = 'OPEN' - * continue - * attributes[category[k]] = values[k] # <<<<<<<<<<<<<< - * d['result'].append(attributes) - * self._lib.ENR_free(ctypes.byref(values)) -*/ - __pyx_t_13 = __Pyx_PyObject_GetItem(__pyx_v_values, __pyx_v_k); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 197, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_13); - __pyx_t_14 = __Pyx_PyObject_GetItem(__pyx_v_category, __pyx_v_k); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 197, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - if (unlikely((PyDict_SetItem(__pyx_v_attributes, __pyx_t_14, __pyx_t_13) < 0))) __PYX_ERR(0, 197, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; - - /* "epanet/epanet.py":190 - * assert length.value == len(category) - * attributes = {} - * for k in range(length.value): # <<<<<<<<<<<<<< - * if category[k] == 'status': - * if values[k] == 2.0: -*/ - __pyx_L7_continue:; - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":198 - * continue - * attributes[category[k]] = values[k] - * d['result'].append(attributes) # <<<<<<<<<<<<<< - * self._lib.ENR_free(ctypes.byref(values)) - * ds.append(d) -*/ - __pyx_t_2 = __Pyx_PyDict_GetItem(__pyx_v_d, __pyx_mstate_global->__pyx_n_u_result); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 198, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_22 = __Pyx_PyObject_Append(__pyx_t_2, __pyx_v_attributes); if (unlikely(__pyx_t_22 == ((int)-1))) __PYX_ERR(0, 198, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":199 - * attributes[category[k]] = values[k] - * d['result'].append(attributes) - * self._lib.ENR_free(ctypes.byref(values)) # <<<<<<<<<<<<<< - * ds.append(d) - * return ds -*/ - __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_v_self, __pyx_mstate_global->__pyx_n_u_lib); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 199, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_14); - __pyx_t_13 = __pyx_t_14; - __Pyx_INCREF(__pyx_t_13); - __pyx_t_17 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_ctypes); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 199, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_12); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_12, __pyx_mstate_global->__pyx_n_u_byref); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 199, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; - __pyx_t_3 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_17 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_17); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_17); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_3 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_17, __pyx_v_values}; - __pyx_t_10 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (__pyx_t_3*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_17); __pyx_t_17 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 199, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - } - __pyx_t_3 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_13, __pyx_t_10}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_ENR_free, __pyx_callargs+__pyx_t_3, (2-__pyx_t_3) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_13); __pyx_t_13 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 199, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":184 - * for i in range(1, size + 1): - * d = { 'link' : links[i - 1], 'result' : [] } - * for j in range(num_periods): # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - } - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - - /* "epanet/epanet.py":200 - * d['result'].append(attributes) - * self._lib.ENR_free(ctypes.byref(values)) - * ds.append(d) # <<<<<<<<<<<<<< - * return ds - * -*/ - __pyx_t_22 = __Pyx_PyList_Append(__pyx_v_ds, __pyx_v_d); if (unlikely(__pyx_t_22 == ((int)-1))) __PYX_ERR(0, 200, __pyx_L1_error) - - /* "epanet/epanet.py":182 - * ds = [] - * - * for i in range(1, size + 1): # <<<<<<<<<<<<<< - * d = { 'link' : links[i - 1], 'result' : [] } - * for j in range(num_periods): -*/ - } - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "epanet/epanet.py":201 - * self._lib.ENR_free(ctypes.byref(values)) - * ds.append(d) - * return ds # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_ds); - __pyx_r = __pyx_v_ds; - goto __pyx_L0; - - /* "epanet/epanet.py":175 - * - * - * def link_results(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['link'] - * num_periods = self.times()['num_periods'] -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_XDECREF(__pyx_t_12); - __Pyx_XDECREF(__pyx_t_13); - __Pyx_XDECREF(__pyx_t_14); - __Pyx_XDECREF(__pyx_t_15); - __Pyx_XDECREF(__pyx_t_16); - __Pyx_XDECREF(__pyx_t_17); - __Pyx_XDECREF(__pyx_t_18); - __Pyx_AddTraceback("epanet.epanet.Output.link_results", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_size); - __Pyx_XDECREF(__pyx_v_num_periods); - __Pyx_XDECREF(__pyx_v_links); - __Pyx_XDECREF(__pyx_v_category); - __Pyx_XDECREF(__pyx_v_ds); - __Pyx_XDECREF(__pyx_v_i); - __Pyx_XDECREF(__pyx_v_d); - __Pyx_XDECREF(__pyx_v_j); - __Pyx_XDECREF(__pyx_v_values); - __Pyx_XDECREF(__pyx_v_length); - __Pyx_XDECREF(__pyx_v_attributes); - __Pyx_XDECREF(__pyx_v_k); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":204 - * - * - * def dump(self) -> dict[str, Any]: # <<<<<<<<<<<<<< - * data = {} - * data |= { 'version' : self.version() } -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_6Output_25dump(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_6Output_25dump = {"dump", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_6Output_25dump, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_6Output_25dump(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_self = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("dump (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_self,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 204, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 204, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "dump", 0) < 0) __PYX_ERR(0, 204, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("dump", 1, 1, 1, i); __PYX_ERR(0, 204, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 204, __pyx_L3_error) - } - __pyx_v_self = values[0]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("dump", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 204, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.Output.dump", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - __pyx_r = __pyx_pf_6epanet_6epanet_6Output_24dump(__pyx_self, __pyx_v_self); - - /* function exit code */ - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6Output_24dump(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_self) { - PyObject *__pyx_v_data = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - size_t __pyx_t_4; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("dump", 0); - - /* "epanet/epanet.py":205 - * - * def dump(self) -> dict[str, Any]: - * data = {} # <<<<<<<<<<<<<< - * data |= { 'version' : self.version() } - * data |= { 'net_size' : self.net_size() } -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 205, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_data = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":206 - * def dump(self) -> dict[str, Any]: - * data = {} - * data |= { 'version' : self.version() } # <<<<<<<<<<<<<< - * data |= { 'net_size' : self.net_size() } - * data |= { 'units' : self.units() } -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 206, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_version, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 206, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_version, __pyx_t_2) < 0) __PYX_ERR(0, 206, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 206, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_2)); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":207 - * data = {} - * data |= { 'version' : self.version() } - * data |= { 'net_size' : self.net_size() } # <<<<<<<<<<<<<< - * data |= { 'units' : self.units() } - * data |= { 'times' : self.times() } -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 207, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_net_size, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 207, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_net_size, __pyx_t_1) < 0) __PYX_ERR(0, 207, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 207, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_1)); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":208 - * data |= { 'version' : self.version() } - * data |= { 'net_size' : self.net_size() } - * data |= { 'units' : self.units() } # <<<<<<<<<<<<<< - * data |= { 'times' : self.times() } - * data |= { 'element_name' : self.element_name() } -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 208, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_units, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 208, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_units, __pyx_t_2) < 0) __PYX_ERR(0, 208, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 208, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_2)); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":209 - * data |= { 'net_size' : self.net_size() } - * data |= { 'units' : self.units() } - * data |= { 'times' : self.times() } # <<<<<<<<<<<<<< - * data |= { 'element_name' : self.element_name() } - * data |= { 'energy_usage' : self.energy_usage() } -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 209, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_times, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 209, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_times, __pyx_t_1) < 0) __PYX_ERR(0, 209, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 209, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_1)); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":210 - * data |= { 'units' : self.units() } - * data |= { 'times' : self.times() } - * data |= { 'element_name' : self.element_name() } # <<<<<<<<<<<<<< - * data |= { 'energy_usage' : self.energy_usage() } - * data |= { 'reactions' : self.reactions() } -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 210, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_element_name, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 210, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_element_name, __pyx_t_2) < 0) __PYX_ERR(0, 210, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 210, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_2)); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":211 - * data |= { 'times' : self.times() } - * data |= { 'element_name' : self.element_name() } - * data |= { 'energy_usage' : self.energy_usage() } # <<<<<<<<<<<<<< - * data |= { 'reactions' : self.reactions() } - * data |= { 'node_results' : self.node_results() } -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 211, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_energy_usage, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 211, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_energy_usage, __pyx_t_1) < 0) __PYX_ERR(0, 211, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 211, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_1)); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":212 - * data |= { 'element_name' : self.element_name() } - * data |= { 'energy_usage' : self.energy_usage() } - * data |= { 'reactions' : self.reactions() } # <<<<<<<<<<<<<< - * data |= { 'node_results' : self.node_results() } - * data |= { 'link_results' : self.link_results() } -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 212, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_reactions, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 212, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_reactions, __pyx_t_2) < 0) __PYX_ERR(0, 212, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 212, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_2)); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":213 - * data |= { 'energy_usage' : self.energy_usage() } - * data |= { 'reactions' : self.reactions() } - * data |= { 'node_results' : self.node_results() } # <<<<<<<<<<<<<< - * data |= { 'link_results' : self.link_results() } - * return data -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 213, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_node_results, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 213, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_node_results, __pyx_t_1) < 0) __PYX_ERR(0, 213, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_1 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_2); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 213, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_1)); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":214 - * data |= { 'reactions' : self.reactions() } - * data |= { 'node_results' : self.node_results() } - * data |= { 'link_results' : self.link_results() } # <<<<<<<<<<<<<< - * return data - * -*/ - __pyx_t_1 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 214, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_3 = __pyx_v_self; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_link_results, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (PyDict_SetItem(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_link_results, __pyx_t_2) < 0) __PYX_ERR(0, 214, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 214, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF_SET(__pyx_v_data, ((PyObject*)__pyx_t_2)); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":215 - * data |= { 'node_results' : self.node_results() } - * data |= { 'link_results' : self.link_results() } - * return data # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_data); - __pyx_r = __pyx_v_data; - goto __pyx_L0; - - /* "epanet/epanet.py":204 - * - * - * def dump(self) -> dict[str, Any]: # <<<<<<<<<<<<<< - * data = {} - * data |= { 'version' : self.version() } -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_AddTraceback("epanet.epanet.Output.dump", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_data); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":218 - * - * - * def _dump_output(path: str) -> dict[str, Any]: # <<<<<<<<<<<<<< - * opt = Output(path) - * data = opt.dump() -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_3_dump_output(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_3_dump_output = {"_dump_output", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_3_dump_output, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_3_dump_output(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_path = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("_dump_output (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_path,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 218, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 218, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "_dump_output", 0) < 0) __PYX_ERR(0, 218, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("_dump_output", 1, 1, 1, i); __PYX_ERR(0, 218, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 218, __pyx_L3_error) - } - __pyx_v_path = ((PyObject*)values[0]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("_dump_output", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 218, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet._dump_output", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_path), (&PyUnicode_Type), 0, "path", 2))) __PYX_ERR(0, 218, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_2_dump_output(__pyx_self, __pyx_v_path); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_2_dump_output(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path) { - PyObject *__pyx_v_opt = NULL; - PyObject *__pyx_v_data = NULL; - PyObject *__pyx_v_f = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - size_t __pyx_t_4; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - int __pyx_t_11; - int __pyx_t_12; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("_dump_output", 0); - - /* "epanet/epanet.py":219 - * - * def _dump_output(path: str) -> dict[str, Any]: - * opt = Output(path) # <<<<<<<<<<<<<< - * data = opt.dump() - * with open(path + '.json', 'w') as f: -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_Output); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 219, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_4 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_v_path}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_4, (2-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 219, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_opt = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":220 - * def _dump_output(path: str) -> dict[str, Any]: - * opt = Output(path) - * data = opt.dump() # <<<<<<<<<<<<<< - * with open(path + '.json', 'w') as f: - * json.dump(data, f) -*/ - __pyx_t_3 = __pyx_v_opt; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_dump, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 220, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_data = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":221 - * opt = Output(path) - * data = opt.dump() - * with open(path + '.json', 'w') as f: # <<<<<<<<<<<<<< - * json.dump(data, f) - * return data -*/ - /*with:*/ { - __pyx_t_3 = NULL; - __Pyx_INCREF(__pyx_builtin_open); - __pyx_t_2 = __pyx_builtin_open; - __pyx_t_5 = __Pyx_PyUnicode_Concat(__pyx_v_path, __pyx_mstate_global->__pyx_kp_u_json); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 221, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_5, __pyx_mstate_global->__pyx_n_u_w}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_4, (3-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 221, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_exit); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 221, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_5 = NULL; - __pyx_t_3 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_enter); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 221, __pyx_L3_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = 1; - #if CYTHON_UNPACK_METHODS - if (likely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_4 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 221, __pyx_L3_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_3 = __pyx_t_2; - __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /*try:*/ { - { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __Pyx_ExceptionSave(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9); - __Pyx_XGOTREF(__pyx_t_7); - __Pyx_XGOTREF(__pyx_t_8); - __Pyx_XGOTREF(__pyx_t_9); - /*try:*/ { - __pyx_v_f = __pyx_t_3; - __pyx_t_3 = 0; - - /* "epanet/epanet.py":222 - * data = opt.dump() - * with open(path + '.json', 'w') as f: - * json.dump(data, f) # <<<<<<<<<<<<<< - * return data - * -*/ - __pyx_t_1 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_json_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 222, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_dump); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 222, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_4 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_1); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_1); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_4 = 0; - } - #endif - { - PyObject *__pyx_callargs[3] = {__pyx_t_1, __pyx_v_data, __pyx_v_f}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_4, (3-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 222, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_3); - } - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":221 - * opt = Output(path) - * data = opt.dump() - * with open(path + '.json', 'w') as f: # <<<<<<<<<<<<<< - * json.dump(data, f) - * return data -*/ - } - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_XDECREF(__pyx_t_8); __pyx_t_8 = 0; - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - goto __pyx_L12_try_end; - __pyx_L7_error:; - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - /*except:*/ { - __Pyx_AddTraceback("epanet.epanet._dump_output", __pyx_clineno, __pyx_lineno, __pyx_filename); - if (__Pyx_GetException(&__pyx_t_3, &__pyx_t_5, &__pyx_t_1) < 0) __PYX_ERR(0, 221, __pyx_L9_except_error) - __Pyx_XGOTREF(__pyx_t_3); - __Pyx_XGOTREF(__pyx_t_5); - __Pyx_XGOTREF(__pyx_t_1); - __pyx_t_2 = PyTuple_Pack(3, __pyx_t_3, __pyx_t_5, __pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 221, __pyx_L9_except_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_2, NULL); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 221, __pyx_L9_except_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_10); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (__pyx_t_11 < 0) __PYX_ERR(0, 221, __pyx_L9_except_error) - __pyx_t_12 = (!__pyx_t_11); - if (unlikely(__pyx_t_12)) { - __Pyx_GIVEREF(__pyx_t_3); - __Pyx_GIVEREF(__pyx_t_5); - __Pyx_XGIVEREF(__pyx_t_1); - __Pyx_ErrRestoreWithState(__pyx_t_3, __pyx_t_5, __pyx_t_1); - __pyx_t_3 = 0; __pyx_t_5 = 0; __pyx_t_1 = 0; - __PYX_ERR(0, 221, __pyx_L9_except_error) - } - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L8_exception_handled; - } - __pyx_L9_except_error:; - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - goto __pyx_L1_error; - __pyx_L8_exception_handled:; - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - __pyx_L12_try_end:; - } - } - /*finally:*/ { - /*normal exit:*/{ - if (__pyx_t_6) { - __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_mstate_global->__pyx_tuple[0], NULL); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 221, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - } - goto __pyx_L6; - } - __pyx_L6:; - } - goto __pyx_L16; - __pyx_L3_error:; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - goto __pyx_L1_error; - __pyx_L16:; - } - - /* "epanet/epanet.py":223 - * with open(path + '.json', 'w') as f: - * json.dump(data, f) - * return data # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - if (!(likely(PyDict_CheckExact(__pyx_v_data))||((__pyx_v_data) == Py_None) || __Pyx_RaiseUnexpectedTypeError("dict", __pyx_v_data))) __PYX_ERR(0, 223, __pyx_L1_error) - __Pyx_INCREF(__pyx_v_data); - __pyx_r = ((PyObject*)__pyx_v_data); - goto __pyx_L0; - - /* "epanet/epanet.py":218 - * - * - * def _dump_output(path: str) -> dict[str, Any]: # <<<<<<<<<<<<<< - * opt = Output(path) - * data = opt.dump() -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_AddTraceback("epanet.epanet._dump_output", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_opt); - __Pyx_XDECREF(__pyx_v_data); - __Pyx_XDECREF(__pyx_v_f); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":226 - * - * - * def dump_output(path: str) -> str: # <<<<<<<<<<<<<< - * data = _dump_output(path) - * return json.dumps(data) -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_5dump_output(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_5dump_output = {"dump_output", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_5dump_output, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_5dump_output(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_path = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("dump_output (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_path,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 226, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 226, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "dump_output", 0) < 0) __PYX_ERR(0, 226, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("dump_output", 1, 1, 1, i); __PYX_ERR(0, 226, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 226, __pyx_L3_error) - } - __pyx_v_path = ((PyObject*)values[0]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("dump_output", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 226, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.dump_output", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_path), (&PyUnicode_Type), 0, "path", 2))) __PYX_ERR(0, 226, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_4dump_output(__pyx_self, __pyx_v_path); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_4dump_output(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path) { - PyObject *__pyx_v_data = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - size_t __pyx_t_4; - PyObject *__pyx_t_5 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("dump_output", 0); - - /* "epanet/epanet.py":227 - * - * def dump_output(path: str) -> str: - * data = _dump_output(path) # <<<<<<<<<<<<<< - * return json.dumps(data) - * -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_dump_output); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 227, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_4 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_v_path}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_4, (2-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 227, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_data = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":228 - * def dump_output(path: str) -> str: - * data = _dump_output(path) - * return json.dumps(data) # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_3 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_json_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 228, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_dumps); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 228, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_4 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_3); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_3); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_4 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, __pyx_v_data}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_4, (2-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 228, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (!(likely(PyUnicode_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None) || __Pyx_RaiseUnexpectedTypeError("str", __pyx_t_1))) __PYX_ERR(0, 228, __pyx_L1_error) - __pyx_r = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "epanet/epanet.py":226 - * - * - * def dump_output(path: str) -> str: # <<<<<<<<<<<<<< - * data = _dump_output(path) - * return json.dumps(data) -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_AddTraceback("epanet.epanet.dump_output", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_data); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":231 - * - * - * def dump_report(path: str) -> str: # <<<<<<<<<<<<<< - * return open(path, 'r').read() - * -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_7dump_report(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_7dump_report = {"dump_report", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_7dump_report, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_7dump_report(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_path = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("dump_report (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_path,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 231, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 231, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "dump_report", 0) < 0) __PYX_ERR(0, 231, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("dump_report", 1, 1, 1, i); __PYX_ERR(0, 231, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 231, __pyx_L3_error) - } - __pyx_v_path = ((PyObject*)values[0]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("dump_report", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 231, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.dump_report", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_path), (&PyUnicode_Type), 0, "path", 2))) __PYX_ERR(0, 231, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_6dump_report(__pyx_self, __pyx_v_path); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_6dump_report(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path) { - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - size_t __pyx_t_6; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("dump_report", 0); - - /* "epanet/epanet.py":232 - * - * def dump_report(path: str) -> str: - * return open(path, 'r').read() # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_4 = NULL; - __Pyx_INCREF(__pyx_builtin_open); - __pyx_t_5 = __pyx_builtin_open; - __pyx_t_6 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_v_path, __pyx_mstate_global->__pyx_n_u_r}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_6, (3-__pyx_t_6) | (__pyx_t_6*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 232, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_2 = __pyx_t_3; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_6 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_read, __pyx_callargs+__pyx_t_6, (1-__pyx_t_6) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 232, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - if (!(likely(PyUnicode_CheckExact(__pyx_t_1))||((__pyx_t_1) == Py_None) || __Pyx_RaiseUnexpectedTypeError("str", __pyx_t_1))) __PYX_ERR(0, 232, __pyx_L1_error) - __pyx_r = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - goto __pyx_L0; - - /* "epanet/epanet.py":231 - * - * - * def dump_report(path: str) -> str: # <<<<<<<<<<<<<< - * return open(path, 'r').read() - * -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_AddTraceback("epanet.epanet.dump_report", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":235 - * - * - * def dump_output_binary(path: str) -> str: # <<<<<<<<<<<<<< - * with open(path, 'rb') as f: - * data = f.read() -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_9dump_output_binary(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_9dump_output_binary = {"dump_output_binary", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_9dump_output_binary, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_9dump_output_binary(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_path = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("dump_output_binary (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_path,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 235, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 235, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "dump_output_binary", 0) < 0) __PYX_ERR(0, 235, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("dump_output_binary", 1, 1, 1, i); __PYX_ERR(0, 235, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 235, __pyx_L3_error) - } - __pyx_v_path = ((PyObject*)values[0]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("dump_output_binary", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 235, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.dump_output_binary", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_path), (&PyUnicode_Type), 0, "path", 2))) __PYX_ERR(0, 235, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_8dump_output_binary(__pyx_self, __pyx_v_path); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_8dump_output_binary(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_path) { - PyObject *__pyx_v_f = NULL; - PyObject *__pyx_v_data = NULL; - PyObject *__pyx_v_bast64_data = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - size_t __pyx_t_4; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - PyObject *__pyx_t_8 = NULL; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - int __pyx_t_11; - int __pyx_t_12; - PyObject *__pyx_t_13 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("dump_output_binary", 0); - - /* "epanet/epanet.py":236 - * - * def dump_output_binary(path: str) -> str: - * with open(path, 'rb') as f: # <<<<<<<<<<<<<< - * data = f.read() - * bast64_data = base64.b64encode(data) -*/ - /*with:*/ { - __pyx_t_2 = NULL; - __Pyx_INCREF(__pyx_builtin_open); - __pyx_t_3 = __pyx_builtin_open; - __pyx_t_4 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_2, __pyx_v_path, __pyx_mstate_global->__pyx_n_u_rb}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_4, (3-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 236, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_5 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_exit); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 236, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_2 = NULL; - __pyx_t_6 = __Pyx_PyObject_LookupSpecial(__pyx_t_1, __pyx_mstate_global->__pyx_n_u_enter); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 236, __pyx_L3_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_4 = 1; - #if CYTHON_UNPACK_METHODS - if (likely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_4 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, NULL}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 236, __pyx_L3_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_6 = __pyx_t_3; - __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /*try:*/ { - { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - __Pyx_ExceptionSave(&__pyx_t_7, &__pyx_t_8, &__pyx_t_9); - __Pyx_XGOTREF(__pyx_t_7); - __Pyx_XGOTREF(__pyx_t_8); - __Pyx_XGOTREF(__pyx_t_9); - /*try:*/ { - __pyx_v_f = __pyx_t_6; - __pyx_t_6 = 0; - - /* "epanet/epanet.py":237 - * def dump_output_binary(path: str) -> str: - * with open(path, 'rb') as f: - * data = f.read() # <<<<<<<<<<<<<< - * bast64_data = base64.b64encode(data) - * return str(bast64_data, 'utf-8') -*/ - __pyx_t_1 = __pyx_v_f; - __Pyx_INCREF(__pyx_t_1); - __pyx_t_4 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, NULL}; - __pyx_t_6 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_read, __pyx_callargs+__pyx_t_4, (1-__pyx_t_4) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 237, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_v_data = __pyx_t_6; - __pyx_t_6 = 0; - - /* "epanet/epanet.py":238 - * with open(path, 'rb') as f: - * data = f.read() - * bast64_data = base64.b64encode(data) # <<<<<<<<<<<<<< - * return str(bast64_data, 'utf-8') - * -*/ - __pyx_t_1 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_base64); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 238, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_b64encode); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 238, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_4 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_2))) { - __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_2); - assert(__pyx_t_1); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_2); - __Pyx_INCREF(__pyx_t_1); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_2, __pyx__function); - __pyx_t_4 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_1, __pyx_v_data}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_4, (2-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 238, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_v_bast64_data = __pyx_t_6; - __pyx_t_6 = 0; - - /* "epanet/epanet.py":239 - * data = f.read() - * bast64_data = base64.b64encode(data) - * return str(bast64_data, 'utf-8') # <<<<<<<<<<<<<< - * - * #DingZQ, 2025-02-04, dict[str, Any] -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = NULL; - __Pyx_INCREF((PyObject *)(&PyUnicode_Type)); - __pyx_t_1 = ((PyObject *)(&PyUnicode_Type)); - __pyx_t_4 = 1; - { - PyObject *__pyx_callargs[3] = {__pyx_t_2, __pyx_v_bast64_data, __pyx_mstate_global->__pyx_kp_u_utf_8}; - __pyx_t_6 = __Pyx_PyObject_FastCall(__pyx_t_1, __pyx_callargs+__pyx_t_4, (3-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 239, __pyx_L7_error) - __Pyx_GOTREF(__pyx_t_6); - } - __pyx_r = ((PyObject*)__pyx_t_6); - __pyx_t_6 = 0; - goto __pyx_L11_try_return; - - /* "epanet/epanet.py":236 - * - * def dump_output_binary(path: str) -> str: - * with open(path, 'rb') as f: # <<<<<<<<<<<<<< - * data = f.read() - * bast64_data = base64.b64encode(data) -*/ - } - __pyx_L7_error:; - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - /*except:*/ { - __Pyx_AddTraceback("epanet.epanet.dump_output_binary", __pyx_clineno, __pyx_lineno, __pyx_filename); - if (__Pyx_GetException(&__pyx_t_6, &__pyx_t_1, &__pyx_t_2) < 0) __PYX_ERR(0, 236, __pyx_L9_except_error) - __Pyx_XGOTREF(__pyx_t_6); - __Pyx_XGOTREF(__pyx_t_1); - __Pyx_XGOTREF(__pyx_t_2); - __pyx_t_3 = PyTuple_Pack(3, __pyx_t_6, __pyx_t_1, __pyx_t_2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 236, __pyx_L9_except_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_10 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_3, NULL); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 236, __pyx_L9_except_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_IsTrue(__pyx_t_10); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (__pyx_t_11 < 0) __PYX_ERR(0, 236, __pyx_L9_except_error) - __pyx_t_12 = (!__pyx_t_11); - if (unlikely(__pyx_t_12)) { - __Pyx_GIVEREF(__pyx_t_6); - __Pyx_GIVEREF(__pyx_t_1); - __Pyx_XGIVEREF(__pyx_t_2); - __Pyx_ErrRestoreWithState(__pyx_t_6, __pyx_t_1, __pyx_t_2); - __pyx_t_6 = 0; __pyx_t_1 = 0; __pyx_t_2 = 0; - __PYX_ERR(0, 236, __pyx_L9_except_error) - } - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - goto __pyx_L8_exception_handled; - } - __pyx_L9_except_error:; - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - goto __pyx_L1_error; - __pyx_L11_try_return:; - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - goto __pyx_L4_return; - __pyx_L8_exception_handled:; - __Pyx_XGIVEREF(__pyx_t_7); - __Pyx_XGIVEREF(__pyx_t_8); - __Pyx_XGIVEREF(__pyx_t_9); - __Pyx_ExceptionReset(__pyx_t_7, __pyx_t_8, __pyx_t_9); - } - } - /*finally:*/ { - /*normal exit:*/{ - if (__pyx_t_5) { - __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_mstate_global->__pyx_tuple[0], NULL); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 236, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - } - goto __pyx_L6; - } - __pyx_L4_return: { - __pyx_t_13 = __pyx_r; - __pyx_r = 0; - if (__pyx_t_5) { - __pyx_t_9 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_mstate_global->__pyx_tuple[0], NULL); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 236, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - } - __pyx_r = __pyx_t_13; - __pyx_t_13 = 0; - goto __pyx_L0; - } - __pyx_L6:; - } - goto __pyx_L16; - __pyx_L3_error:; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - goto __pyx_L1_error; - __pyx_L16:; - } - - /* "epanet/epanet.py":235 - * - * - * def dump_output_binary(path: str) -> str: # <<<<<<<<<<<<<< - * with open(path, 'rb') as f: - * data = f.read() -*/ - - /* function exit code */ - __pyx_r = ((PyObject*)Py_None); __Pyx_INCREF(Py_None); - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_AddTraceback("epanet.epanet.dump_output_binary", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_f); - __Pyx_XDECREF(__pyx_v_data); - __Pyx_XDECREF(__pyx_v_bast64_data); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":242 - * - * #DingZQ, 2025-02-04, dict[str, Any] - * def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: # <<<<<<<<<<<<<< - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_11run_project_return_dict(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_11run_project_return_dict = {"run_project_return_dict", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_11run_project_return_dict, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_11run_project_return_dict(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_name = 0; - PyObject *__pyx_v_readable_output = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[2] = {0,0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("run_project_return_dict (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_name,&__pyx_mstate_global->__pyx_n_u_readable_output,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 242, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 2: - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 242, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 242, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "run_project_return_dict", 0) < 0) __PYX_ERR(0, 242, __pyx_L3_error) - if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject *)Py_False))); - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("run_project_return_dict", 0, 1, 2, i); __PYX_ERR(0, 242, __pyx_L3_error) } - } - } else { - switch (__pyx_nargs) { - case 2: - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 242, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 242, __pyx_L3_error) - break; - default: goto __pyx_L5_argtuple_error; - } - if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject *)Py_False))); - } - __pyx_v_name = ((PyObject*)values[0]); - __pyx_v_readable_output = values[1]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("run_project_return_dict", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 242, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.run_project_return_dict", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyUnicode_Type), 0, "name", 2))) __PYX_ERR(0, 242, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_10run_project_return_dict(__pyx_self, __pyx_v_name, __pyx_v_readable_output); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_10run_project_return_dict(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_name, PyObject *__pyx_v_readable_output) { - PyObject *__pyx_v_dir = NULL; - PyObject *__pyx_v_db_inp = NULL; - PyObject *__pyx_v_input = NULL; - PyObject *__pyx_v_exe = NULL; - PyObject *__pyx_v_inp = NULL; - PyObject *__pyx_v_rpt = NULL; - PyObject *__pyx_v_opt = NULL; - PyObject *__pyx_v_command = NULL; - PyObject *__pyx_v_data = NULL; - PyObject *__pyx_v_result = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - size_t __pyx_t_5; - int __pyx_t_6; - int __pyx_t_7; - PyObject *__pyx_t_8[3]; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12[7]; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("run_project_return_dict", 0); - - /* "epanet/epanet.py":243 - * #DingZQ, 2025-02-04, dict[str, Any] - * def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: - * if not project.have_project(name): # <<<<<<<<<<<<<< - * raise Exception(f'Not found project [{name}]') - * -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_project); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 243, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_have_project); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 243, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_v_name}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 243, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 243, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_7 = (!__pyx_t_6); - if (unlikely(__pyx_t_7)) { - - /* "epanet/epanet.py":244 - * def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') # <<<<<<<<<<<<<< - * - * dir = os.path.abspath(os.getcwd()) -*/ - __pyx_t_4 = NULL; - __Pyx_INCREF((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_2 = ((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_8[0] = __pyx_mstate_global->__pyx_kp_u_Not_found_project; - __pyx_t_8[1] = __pyx_v_name; - __pyx_t_8[2] = __pyx_mstate_global->__pyx_kp_u_; - __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_8, 3, 19 + __Pyx_PyUnicode_GET_LENGTH(__pyx_v_name) + 1, 127 | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_v_name)); - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 244, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_5 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 244, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_Raise(__pyx_t_1, 0, 0, 0); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __PYX_ERR(0, 244, __pyx_L1_error) - - /* "epanet/epanet.py":243 - * #DingZQ, 2025-02-04, dict[str, Any] - * def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: - * if not project.have_project(name): # <<<<<<<<<<<<<< - * raise Exception(f'Not found project [{name}]') - * -*/ - } - - /* "epanet/epanet.py":246 - * raise Exception(f'Not found project [{name}]') - * - * dir = os.path.abspath(os.getcwd()) # <<<<<<<<<<<<<< - * - * db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 246, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 246, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_2 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 246, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_getcwd); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 246, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, NULL}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (1-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 246, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_abspath, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 246, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_dir = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":248 - * dir = os.path.abspath(os.getcwd()) - * - * db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') # <<<<<<<<<<<<<< - * inp_out.dump_inp(name, db_inp, '2') - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 248, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 248, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_4 = __pyx_t_2; - __Pyx_INCREF(__pyx_t_4); - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 248, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 248, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_11 = __pyx_t_10; - __Pyx_INCREF(__pyx_t_11); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_11, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_db_inp}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 248, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_10 = __Pyx_PyUnicode_Concat(__pyx_v_name, __pyx_mstate_global->__pyx_kp_u_db_inp_2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 248, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_t_3, __pyx_t_10}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 248, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_db_inp = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":249 - * - * db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') - * inp_out.dump_inp(name, db_inp, '2') # <<<<<<<<<<<<<< - * - * input = name + '.db' -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_inp_out); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 249, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_dump_inp); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 249, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[4] = {__pyx_t_2, __pyx_v_name, __pyx_v_db_inp, __pyx_mstate_global->__pyx_kp_u_2}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_5, (4-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 249, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":251 - * inp_out.dump_inp(name, db_inp, '2') - * - * input = name + '.db' # <<<<<<<<<<<<<< - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') -*/ - __pyx_t_1 = __Pyx_PyUnicode_Concat(__pyx_v_name, __pyx_mstate_global->__pyx_kp_u_db); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 251, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_input = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":252 - * - * input = name + '.db' - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') # <<<<<<<<<<<<<< - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 252, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 252, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_3 = __pyx_t_10; - __Pyx_INCREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 252, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 252, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_4 = __pyx_t_9; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_epanet}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 252, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_2, __pyx_mstate_global->__pyx_kp_u_runepanet_exe}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 252, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_exe = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":253 - * input = name + '.db' - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') # <<<<<<<<<<<<<< - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 253, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 253, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_10 = __pyx_t_3; - __Pyx_INCREF(__pyx_t_10); - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 253, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 253, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_9 = __pyx_t_11; - __Pyx_INCREF(__pyx_t_9); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_9, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_db_inp}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 253, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_11 = __Pyx_PyUnicode_Concat(__pyx_v_input, __pyx_mstate_global->__pyx_kp_u_inp); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 253, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_10, __pyx_t_2, __pyx_t_11}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 253, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_inp = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":254 - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') # <<<<<<<<<<<<<< - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') - * command = f'{exe} {inp} {rpt} {opt}' -*/ - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 254, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 254, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_3 = __pyx_t_2; - __Pyx_INCREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 254, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 254, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_10 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_10); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_10, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_temp}; - __pyx_t_11 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 254, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - } - __pyx_t_4 = __Pyx_PyUnicode_Concat(__pyx_v_input, __pyx_mstate_global->__pyx_kp_u_rpt); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 254, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_11, __pyx_t_4}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 254, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_rpt = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":255 - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') # <<<<<<<<<<<<<< - * command = f'{exe} {inp} {rpt} {opt}' - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 255, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 255, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_2 = __pyx_t_11; - __Pyx_INCREF(__pyx_t_2); - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 255, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 255, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_3 = __pyx_t_9; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_temp}; - __pyx_t_4 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 255, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - __pyx_t_9 = __Pyx_PyUnicode_Concat(__pyx_v_input, __pyx_mstate_global->__pyx_kp_u_opt); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 255, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_2, __pyx_t_4, __pyx_t_9}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 255, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_opt = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":256 - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') - * command = f'{exe} {inp} {rpt} {opt}' # <<<<<<<<<<<<<< - * - * data = {} -*/ - __pyx_t_1 = __Pyx_PyObject_FormatSimple(__pyx_v_exe, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 256, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_inp, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 256, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_9 = __Pyx_PyObject_FormatSimple(__pyx_v_rpt, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 256, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_v_opt, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 256, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_12[0] = __pyx_t_1; - __pyx_t_12[1] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_12[2] = __pyx_t_11; - __pyx_t_12[3] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_12[4] = __pyx_t_9; - __pyx_t_12[5] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_12[6] = __pyx_t_4; - __pyx_t_2 = __Pyx_PyUnicode_Join(__pyx_t_12, 7, __Pyx_PyUnicode_GET_LENGTH(__pyx_t_1) + 1 * 3 + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11) + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_9) + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4), 127 | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_1) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_9) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_4)); - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 256, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_v_command = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":258 - * command = f'{exe} {inp} {rpt} {opt}' - * - * data = {} # <<<<<<<<<<<<<< - * - * result = os.system(command) -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 258, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_v_data = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":260 - * data = {} - * - * result = os.system(command) # <<<<<<<<<<<<<< - * if result != 0: - * data['simulation_result'] = 'failed' -*/ - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 260, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_system); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 260, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_v_command}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 260, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_v_result = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":261 - * - * result = os.system(command) - * if result != 0: # <<<<<<<<<<<<<< - * data['simulation_result'] = 'failed' - * else: -*/ - __pyx_t_7 = (__Pyx_PyLong_BoolNeObjC(__pyx_v_result, __pyx_mstate_global->__pyx_int_0, 0, 0)); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 261, __pyx_L1_error) - if (__pyx_t_7) { - - /* "epanet/epanet.py":262 - * result = os.system(command) - * if result != 0: - * data['simulation_result'] = 'failed' # <<<<<<<<<<<<<< - * else: - * data['simulation_result'] = 'successful' -*/ - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_simulation_result, __pyx_mstate_global->__pyx_n_u_failed) < 0))) __PYX_ERR(0, 262, __pyx_L1_error) - - /* "epanet/epanet.py":261 - * - * result = os.system(command) - * if result != 0: # <<<<<<<<<<<<<< - * data['simulation_result'] = 'failed' - * else: -*/ - goto __pyx_L4; - } - - /* "epanet/epanet.py":264 - * data['simulation_result'] = 'failed' - * else: - * data['simulation_result'] = 'successful' # <<<<<<<<<<<<<< - * if readable_output: - * data ['output'] = _dump_output(opt) -*/ - /*else*/ { - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_simulation_result, __pyx_mstate_global->__pyx_n_u_successful) < 0))) __PYX_ERR(0, 264, __pyx_L1_error) - - /* "epanet/epanet.py":265 - * else: - * data['simulation_result'] = 'successful' - * if readable_output: # <<<<<<<<<<<<<< - * data ['output'] = _dump_output(opt) - * else: -*/ - __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_v_readable_output); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 265, __pyx_L1_error) - if (__pyx_t_7) { - - /* "epanet/epanet.py":266 - * data['simulation_result'] = 'successful' - * if readable_output: - * data ['output'] = _dump_output(opt) # <<<<<<<<<<<<<< - * else: - * data['output'] = dump_output_binary(opt) -*/ - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_dump_output); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 266, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_opt}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 266, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_output, __pyx_t_2) < 0))) __PYX_ERR(0, 266, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":265 - * else: - * data['simulation_result'] = 'successful' - * if readable_output: # <<<<<<<<<<<<<< - * data ['output'] = _dump_output(opt) - * else: -*/ - goto __pyx_L5; - } - - /* "epanet/epanet.py":268 - * data ['output'] = _dump_output(opt) - * else: - * data['output'] = dump_output_binary(opt) # <<<<<<<<<<<<<< - * - * data['report'] = dump_report(rpt) -*/ - /*else*/ { - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_dump_output_binary); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 268, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_v_opt}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 268, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_output, __pyx_t_2) < 0))) __PYX_ERR(0, 268, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - } - __pyx_L5:; - } - __pyx_L4:; - - /* "epanet/epanet.py":270 - * data['output'] = dump_output_binary(opt) - * - * data['report'] = dump_report(rpt) # <<<<<<<<<<<<<< - * - * return data -*/ - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_dump_report); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 270, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_rpt}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 270, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_report, __pyx_t_2) < 0))) __PYX_ERR(0, 270, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":272 - * data['report'] = dump_report(rpt) - * - * return data # <<<<<<<<<<<<<< - * - * # original code -*/ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(__pyx_v_data); - __pyx_r = __pyx_v_data; - goto __pyx_L0; - - /* "epanet/epanet.py":242 - * - * #DingZQ, 2025-02-04, dict[str, Any] - * def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: # <<<<<<<<<<<<<< - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_AddTraceback("epanet.epanet.run_project_return_dict", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_dir); - __Pyx_XDECREF(__pyx_v_db_inp); - __Pyx_XDECREF(__pyx_v_input); - __Pyx_XDECREF(__pyx_v_exe); - __Pyx_XDECREF(__pyx_v_inp); - __Pyx_XDECREF(__pyx_v_rpt); - __Pyx_XDECREF(__pyx_v_opt); - __Pyx_XDECREF(__pyx_v_command); - __Pyx_XDECREF(__pyx_v_data); - __Pyx_XDECREF(__pyx_v_result); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":275 - * - * # original code - * def run_project(name: str, readable_output: bool = False) -> str: # <<<<<<<<<<<<<< - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_13run_project(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_13run_project = {"run_project", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_13run_project, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_13run_project(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_name = 0; - PyObject *__pyx_v_readable_output = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[2] = {0,0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("run_project (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_name,&__pyx_mstate_global->__pyx_n_u_readable_output,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 275, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 2: - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 275, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 275, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "run_project", 0) < 0) __PYX_ERR(0, 275, __pyx_L3_error) - if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject *)Py_False))); - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("run_project", 0, 1, 2, i); __PYX_ERR(0, 275, __pyx_L3_error) } - } - } else { - switch (__pyx_nargs) { - case 2: - values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 275, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 275, __pyx_L3_error) - break; - default: goto __pyx_L5_argtuple_error; - } - if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject *)Py_False))); - } - __pyx_v_name = ((PyObject*)values[0]); - __pyx_v_readable_output = values[1]; - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("run_project", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 275, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.run_project", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyUnicode_Type), 0, "name", 2))) __PYX_ERR(0, 275, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_12run_project(__pyx_self, __pyx_v_name, __pyx_v_readable_output); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_12run_project(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_name, PyObject *__pyx_v_readable_output) { - PyObject *__pyx_v_dir = NULL; - PyObject *__pyx_v_db_inp = NULL; - PyObject *__pyx_v_input = NULL; - PyObject *__pyx_v_exe = NULL; - PyObject *__pyx_v_inp = NULL; - PyObject *__pyx_v_rpt = NULL; - PyObject *__pyx_v_opt = NULL; - PyObject *__pyx_v_command = NULL; - PyObject *__pyx_v_data = NULL; - PyObject *__pyx_v_result = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - size_t __pyx_t_5; - int __pyx_t_6; - int __pyx_t_7; - PyObject *__pyx_t_8[3]; - PyObject *__pyx_t_9 = NULL; - PyObject *__pyx_t_10 = NULL; - PyObject *__pyx_t_11 = NULL; - PyObject *__pyx_t_12[7]; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("run_project", 0); - - /* "epanet/epanet.py":276 - * # original code - * def run_project(name: str, readable_output: bool = False) -> str: - * if not project.have_project(name): # <<<<<<<<<<<<<< - * raise Exception(f'Not found project [{name}]') - * -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_project); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 276, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_have_project); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 276, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_v_name}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 276, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_t_6 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely((__pyx_t_6 < 0))) __PYX_ERR(0, 276, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __pyx_t_7 = (!__pyx_t_6); - if (unlikely(__pyx_t_7)) { - - /* "epanet/epanet.py":277 - * def run_project(name: str, readable_output: bool = False) -> str: - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') # <<<<<<<<<<<<<< - * - * dir = os.path.abspath(os.getcwd()) -*/ - __pyx_t_4 = NULL; - __Pyx_INCREF((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_2 = ((PyObject *)(((PyTypeObject*)PyExc_Exception))); - __pyx_t_8[0] = __pyx_mstate_global->__pyx_kp_u_Not_found_project; - __pyx_t_8[1] = __pyx_v_name; - __pyx_t_8[2] = __pyx_mstate_global->__pyx_kp_u_; - __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_8, 3, 19 + __Pyx_PyUnicode_GET_LENGTH(__pyx_v_name) + 1, 127 | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_v_name)); - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 277, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_5 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 277, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_Raise(__pyx_t_1, 0, 0, 0); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __PYX_ERR(0, 277, __pyx_L1_error) - - /* "epanet/epanet.py":276 - * # original code - * def run_project(name: str, readable_output: bool = False) -> str: - * if not project.have_project(name): # <<<<<<<<<<<<<< - * raise Exception(f'Not found project [{name}]') - * -*/ - } - - /* "epanet/epanet.py":279 - * raise Exception(f'Not found project [{name}]') - * - * dir = os.path.abspath(os.getcwd()) # <<<<<<<<<<<<<< - * - * db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 279, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 279, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_2 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_9 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 279, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_getcwd); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 279, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_9 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_9); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_9); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_9, NULL}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (1-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 279, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_abspath, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 279, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_dir = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":281 - * dir = os.path.abspath(os.getcwd()) - * - * db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') # <<<<<<<<<<<<<< - * inp_out.dump_inp(name, db_inp, '2') - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_4 = __pyx_t_2; - __Pyx_INCREF(__pyx_t_4); - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_11 = __pyx_t_10; - __Pyx_INCREF(__pyx_t_11); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_11, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_db_inp}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_10 = __Pyx_PyUnicode_Concat(__pyx_v_name, __pyx_mstate_global->__pyx_kp_u_db_inp_2); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_t_3, __pyx_t_10}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 281, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_db_inp = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":282 - * - * db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') - * inp_out.dump_inp(name, db_inp, '2') # <<<<<<<<<<<<<< - * - * input = name + '.db' -*/ - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_inp_out); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 282, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_dump_inp); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 282, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_3))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_3, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[4] = {__pyx_t_2, __pyx_v_name, __pyx_v_db_inp, __pyx_mstate_global->__pyx_kp_u_2}; - __pyx_t_1 = __Pyx_PyObject_FastCall(__pyx_t_3, __pyx_callargs+__pyx_t_5, (4-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 282, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - - /* "epanet/epanet.py":284 - * inp_out.dump_inp(name, db_inp, '2') - * - * input = name + '.db' # <<<<<<<<<<<<<< - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') -*/ - __pyx_t_1 = __Pyx_PyUnicode_Concat(__pyx_v_name, __pyx_mstate_global->__pyx_kp_u_db); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 284, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_v_input = ((PyObject*)__pyx_t_1); - __pyx_t_1 = 0; - - /* "epanet/epanet.py":285 - * - * input = name + '.db' - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') # <<<<<<<<<<<<<< - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 285, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_10 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 285, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_3 = __pyx_t_10; - __Pyx_INCREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 285, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 285, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_4 = __pyx_t_9; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_epanet}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 285, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_2, __pyx_mstate_global->__pyx_kp_u_runepanet_exe}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 285, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_exe = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":286 - * input = name + '.db' - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') # <<<<<<<<<<<<<< - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 286, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 286, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_10 = __pyx_t_3; - __Pyx_INCREF(__pyx_t_10); - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 286, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 286, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_9 = __pyx_t_11; - __Pyx_INCREF(__pyx_t_9); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_9, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_db_inp}; - __pyx_t_2 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 286, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_11 = __Pyx_PyUnicode_Concat(__pyx_v_input, __pyx_mstate_global->__pyx_kp_u_inp); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 286, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_10, __pyx_t_2, __pyx_t_11}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 286, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_inp = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":287 - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') # <<<<<<<<<<<<<< - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') - * command = f'{exe} {inp} {rpt} {opt}' -*/ - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 287, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 287, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_3 = __pyx_t_2; - __Pyx_INCREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 287, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 287, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_10 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_10); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_10, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_temp}; - __pyx_t_11 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 287, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - } - __pyx_t_4 = __Pyx_PyUnicode_Concat(__pyx_v_input, __pyx_mstate_global->__pyx_kp_u_rpt); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 287, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_11, __pyx_t_4}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 287, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_rpt = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":288 - * inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') # <<<<<<<<<<<<<< - * command = f'{exe} {inp} {rpt} {opt}' - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 288, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 288, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_t_2 = __pyx_t_11; - __Pyx_INCREF(__pyx_t_2); - __Pyx_GetModuleGlobalName(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 288, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_10); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_10, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 288, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; - __pyx_t_3 = __pyx_t_9; - __Pyx_INCREF(__pyx_t_3); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_temp}; - __pyx_t_4 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 288, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - __pyx_t_9 = __Pyx_PyUnicode_Concat(__pyx_v_input, __pyx_mstate_global->__pyx_kp_u_opt); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 288, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_5 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_2, __pyx_t_4, __pyx_t_9}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_5, (3-__pyx_t_5) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 288, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_opt = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":289 - * rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') - * command = f'{exe} {inp} {rpt} {opt}' # <<<<<<<<<<<<<< - * - * data = {} -*/ - __pyx_t_1 = __Pyx_PyObject_FormatSimple(__pyx_v_exe, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 289, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_11 = __Pyx_PyObject_FormatSimple(__pyx_v_inp, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 289, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_9 = __Pyx_PyObject_FormatSimple(__pyx_v_rpt, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 289, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_4 = __Pyx_PyObject_FormatSimple(__pyx_v_opt, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 289, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_12[0] = __pyx_t_1; - __pyx_t_12[1] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_12[2] = __pyx_t_11; - __pyx_t_12[3] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_12[4] = __pyx_t_9; - __pyx_t_12[5] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_12[6] = __pyx_t_4; - __pyx_t_2 = __Pyx_PyUnicode_Join(__pyx_t_12, 7, __Pyx_PyUnicode_GET_LENGTH(__pyx_t_1) + 1 * 3 + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_11) + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_9) + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_4), 127 | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_1) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_11) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_9) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_4)); - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 289, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - __pyx_v_command = ((PyObject*)__pyx_t_2); - __pyx_t_2 = 0; - - /* "epanet/epanet.py":291 - * command = f'{exe} {inp} {rpt} {opt}' - * - * data = {} # <<<<<<<<<<<<<< - * - * result = os.system(command) -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 291, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_v_data = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":293 - * data = {} - * - * result = os.system(command) # <<<<<<<<<<<<<< - * if result != 0: - * data['simulation_result'] = 'failed' -*/ - __pyx_t_4 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 293, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __pyx_t_11 = __Pyx_PyObject_GetAttrStr(__pyx_t_9, __pyx_mstate_global->__pyx_n_u_system); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 293, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_4); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_4); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_4, __pyx_v_command}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 293, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_v_result = __pyx_t_2; - __pyx_t_2 = 0; - - /* "epanet/epanet.py":294 - * - * result = os.system(command) - * if result != 0: # <<<<<<<<<<<<<< - * data['simulation_result'] = 'failed' - * else: -*/ - __pyx_t_7 = (__Pyx_PyLong_BoolNeObjC(__pyx_v_result, __pyx_mstate_global->__pyx_int_0, 0, 0)); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 294, __pyx_L1_error) - if (__pyx_t_7) { - - /* "epanet/epanet.py":295 - * result = os.system(command) - * if result != 0: - * data['simulation_result'] = 'failed' # <<<<<<<<<<<<<< - * else: - * data['simulation_result'] = 'successful' -*/ - if (unlikely((PyObject_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_simulation_result, __pyx_mstate_global->__pyx_n_u_failed) < 0))) __PYX_ERR(0, 295, __pyx_L1_error) - - /* "epanet/epanet.py":294 - * - * result = os.system(command) - * if result != 0: # <<<<<<<<<<<<<< - * data['simulation_result'] = 'failed' - * else: -*/ - goto __pyx_L4; - } - - /* "epanet/epanet.py":297 - * data['simulation_result'] = 'failed' - * else: - * data['simulation_result'] = 'successful' # <<<<<<<<<<<<<< - * if readable_output: - * data |= _dump_output(opt) -*/ - /*else*/ { - if (unlikely((PyObject_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_simulation_result, __pyx_mstate_global->__pyx_n_u_successful) < 0))) __PYX_ERR(0, 297, __pyx_L1_error) - - /* "epanet/epanet.py":298 - * else: - * data['simulation_result'] = 'successful' - * if readable_output: # <<<<<<<<<<<<<< - * data |= _dump_output(opt) - * else: -*/ - __pyx_t_7 = __Pyx_PyObject_IsTrue(__pyx_v_readable_output); if (unlikely((__pyx_t_7 < 0))) __PYX_ERR(0, 298, __pyx_L1_error) - if (__pyx_t_7) { - - /* "epanet/epanet.py":299 - * data['simulation_result'] = 'successful' - * if readable_output: - * data |= _dump_output(opt) # <<<<<<<<<<<<<< - * else: - * data['output'] = dump_output_binary(opt) -*/ - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_4, __pyx_mstate_global->__pyx_n_u_dump_output); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 299, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_4))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_4); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_4); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_4, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_opt}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_4, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 299, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __pyx_t_4 = PyNumber_InPlaceOr(__pyx_v_data, __pyx_t_2); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 299, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF_SET(__pyx_v_data, __pyx_t_4); - __pyx_t_4 = 0; - - /* "epanet/epanet.py":298 - * else: - * data['simulation_result'] = 'successful' - * if readable_output: # <<<<<<<<<<<<<< - * data |= _dump_output(opt) - * else: -*/ - goto __pyx_L5; - } - - /* "epanet/epanet.py":301 - * data |= _dump_output(opt) - * else: - * data['output'] = dump_output_binary(opt) # <<<<<<<<<<<<<< - * - * data['report'] = dump_report(rpt) -*/ - /*else*/ { - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_dump_output_binary); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 301, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_11))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_11); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_11); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_11, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_v_opt}; - __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_11, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 301, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - if (unlikely((PyObject_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_output, __pyx_t_4) < 0))) __PYX_ERR(0, 301, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - } - __pyx_L5:; - } - __pyx_L4:; - - /* "epanet/epanet.py":303 - * data['output'] = dump_output_binary(opt) - * - * data['report'] = dump_report(rpt) # <<<<<<<<<<<<<< - * - * return json.dumps(data) -*/ - __pyx_t_11 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_dump_report); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 303, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_2))) { - __pyx_t_11 = PyMethod_GET_SELF(__pyx_t_2); - assert(__pyx_t_11); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_2); - __Pyx_INCREF(__pyx_t_11); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_2, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_11, __pyx_v_rpt}; - __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_2, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_11); __pyx_t_11 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 303, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - if (unlikely((PyObject_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_report, __pyx_t_4) < 0))) __PYX_ERR(0, 303, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - - /* "epanet/epanet.py":305 - * data['report'] = dump_report(rpt) - * - * return json.dumps(data) # <<<<<<<<<<<<<< - * - * -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_json_2); if (unlikely(!__pyx_t_11)) __PYX_ERR(0, 305, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_11); - __pyx_t_9 = __Pyx_PyObject_GetAttrStr(__pyx_t_11, __pyx_mstate_global->__pyx_n_u_dumps); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 305, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_9); - __Pyx_DECREF(__pyx_t_11); __pyx_t_11 = 0; - __pyx_t_5 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_9))) { - __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_9); - assert(__pyx_t_2); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_9); - __Pyx_INCREF(__pyx_t_2); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_9, __pyx__function); - __pyx_t_5 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_v_data}; - __pyx_t_4 = __Pyx_PyObject_FastCall(__pyx_t_9, __pyx_callargs+__pyx_t_5, (2-__pyx_t_5) | (__pyx_t_5*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; - if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 305, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - } - if (!(likely(PyUnicode_CheckExact(__pyx_t_4))||((__pyx_t_4) == Py_None) || __Pyx_RaiseUnexpectedTypeError("str", __pyx_t_4))) __PYX_ERR(0, 305, __pyx_L1_error) - __pyx_r = ((PyObject*)__pyx_t_4); - __pyx_t_4 = 0; - goto __pyx_L0; - - /* "epanet/epanet.py":275 - * - * # original code - * def run_project(name: str, readable_output: bool = False) -> str: # <<<<<<<<<<<<<< - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_9); - __Pyx_XDECREF(__pyx_t_10); - __Pyx_XDECREF(__pyx_t_11); - __Pyx_AddTraceback("epanet.epanet.run_project", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_dir); - __Pyx_XDECREF(__pyx_v_db_inp); - __Pyx_XDECREF(__pyx_v_input); - __Pyx_XDECREF(__pyx_v_exe); - __Pyx_XDECREF(__pyx_v_inp); - __Pyx_XDECREF(__pyx_v_rpt); - __Pyx_XDECREF(__pyx_v_opt); - __Pyx_XDECREF(__pyx_v_command); - __Pyx_XDECREF(__pyx_v_data); - __Pyx_XDECREF(__pyx_v_result); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -/* "epanet/epanet.py":308 - * - * - * def run_inp(name: str) -> str: # <<<<<<<<<<<<<< - * dir = os.path.abspath(os.getcwd()) - * -*/ - -/* Python wrapper */ -static PyObject *__pyx_pw_6epanet_6epanet_15run_inp(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -); /*proto*/ -static PyMethodDef __pyx_mdef_6epanet_6epanet_15run_inp = {"run_inp", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_6epanet_6epanet_15run_inp, __Pyx_METH_FASTCALL|METH_KEYWORDS, 0}; -static PyObject *__pyx_pw_6epanet_6epanet_15run_inp(PyObject *__pyx_self, -#if CYTHON_METH_FASTCALL -PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds -#else -PyObject *__pyx_args, PyObject *__pyx_kwds -#endif -) { - PyObject *__pyx_v_name = 0; - #if !CYTHON_METH_FASTCALL - CYTHON_UNUSED Py_ssize_t __pyx_nargs; - #endif - CYTHON_UNUSED PyObject *const *__pyx_kwvalues; - PyObject* values[1] = {0}; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - PyObject *__pyx_r = 0; - __Pyx_RefNannyDeclarations - __Pyx_RefNannySetupContext("run_inp (wrapper)", 0); - #if !CYTHON_METH_FASTCALL - #if CYTHON_ASSUME_SAFE_SIZE - __pyx_nargs = PyTuple_GET_SIZE(__pyx_args); - #else - __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL; - #endif - #endif - __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs); - { - PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_name,0}; - const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0; - if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 308, __pyx_L3_error) - if (__pyx_kwds_len > 0) { - switch (__pyx_nargs) { - case 1: - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 308, __pyx_L3_error) - CYTHON_FALLTHROUGH; - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - const Py_ssize_t kwd_pos_args = __pyx_nargs; - if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "run_inp", 0) < 0) __PYX_ERR(0, 308, __pyx_L3_error) - for (Py_ssize_t i = __pyx_nargs; i < 1; i++) { - if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("run_inp", 1, 1, 1, i); __PYX_ERR(0, 308, __pyx_L3_error) } - } - } else if (unlikely(__pyx_nargs != 1)) { - goto __pyx_L5_argtuple_error; - } else { - values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0); - if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 308, __pyx_L3_error) - } - __pyx_v_name = ((PyObject*)values[0]); - } - goto __pyx_L6_skip; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("run_inp", 1, 1, 1, __pyx_nargs); __PYX_ERR(0, 308, __pyx_L3_error) - __pyx_L6_skip:; - goto __pyx_L4_argument_unpacking_done; - __pyx_L3_error:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __Pyx_AddTraceback("epanet.epanet.run_inp", __pyx_clineno, __pyx_lineno, __pyx_filename); - __Pyx_RefNannyFinishContext(); - return NULL; - __pyx_L4_argument_unpacking_done:; - if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_name), (&PyUnicode_Type), 0, "name", 2))) __PYX_ERR(0, 308, __pyx_L1_error) - __pyx_r = __pyx_pf_6epanet_6epanet_14run_inp(__pyx_self, __pyx_v_name); - - /* function exit code */ - goto __pyx_L0; - __pyx_L1_error:; - __pyx_r = NULL; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - goto __pyx_L7_cleaned_up; - __pyx_L0:; - for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) { - Py_XDECREF(values[__pyx_temp]); - } - __pyx_L7_cleaned_up:; - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} - -static PyObject *__pyx_pf_6epanet_6epanet_14run_inp(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_name) { - PyObject *__pyx_v_dir = NULL; - PyObject *__pyx_v_exe = NULL; - PyObject *__pyx_v_inp = NULL; - PyObject *__pyx_v_rpt = NULL; - PyObject *__pyx_v_opt = NULL; - PyObject *__pyx_v_command = NULL; - PyObject *__pyx_v_data = NULL; - PyObject *__pyx_v_result = NULL; - PyObject *__pyx_r = NULL; - __Pyx_RefNannyDeclarations - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - PyObject *__pyx_t_4 = NULL; - PyObject *__pyx_t_5 = NULL; - PyObject *__pyx_t_6 = NULL; - PyObject *__pyx_t_7 = NULL; - size_t __pyx_t_8; - PyObject *__pyx_t_9[7]; - int __pyx_t_10; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannySetupContext("run_inp", 0); - - /* "epanet/epanet.py":309 - * - * def run_inp(name: str) -> str: - * dir = os.path.abspath(os.getcwd()) # <<<<<<<<<<<<<< - * - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 309, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 309, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_2 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_5 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 309, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_getcwd); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 309, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_7))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_7); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_7); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_7, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, NULL}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+__pyx_t_8, (1-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 309, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[2] = {__pyx_t_2, __pyx_t_3}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_abspath, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 309, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_dir = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":311 - * dir = os.path.abspath(os.getcwd()) - * - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') # <<<<<<<<<<<<<< - * inp = os.path.join(os.path.join(dir, 'inp'), name + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), name + '.rpt') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 311, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 311, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_4 = __pyx_t_2; - __Pyx_INCREF(__pyx_t_4); - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 311, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 311, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_7 = __pyx_t_6; - __Pyx_INCREF(__pyx_t_7); - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_7, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_epanet}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 311, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_t_3, __pyx_mstate_global->__pyx_kp_u_runepanet_exe}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 311, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_exe = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":312 - * - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'inp'), name + '.inp') # <<<<<<<<<<<<<< - * rpt = os.path.join(os.path.join(dir, 'temp'), name + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), name + '.opt') -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 312, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 312, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_4); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_2 = __pyx_t_4; - __Pyx_INCREF(__pyx_t_2); - __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 312, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 312, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_t_6 = __pyx_t_5; - __Pyx_INCREF(__pyx_t_6); - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_6, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_inp_2}; - __pyx_t_3 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 312, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_t_5 = __Pyx_PyUnicode_Concat(__pyx_v_name, __pyx_mstate_global->__pyx_kp_u_inp); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 312, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_2, __pyx_t_3, __pyx_t_5}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 312, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_inp = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":313 - * exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - * inp = os.path.join(os.path.join(dir, 'inp'), name + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), name + '.rpt') # <<<<<<<<<<<<<< - * opt = os.path.join(os.path.join(dir, 'temp'), name + '.opt') - * command = f'{exe} {inp} {rpt} {opt}' -*/ - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 313, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 313, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __pyx_t_4 = __pyx_t_3; - __Pyx_INCREF(__pyx_t_4); - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 313, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 313, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_2 = __pyx_t_7; - __Pyx_INCREF(__pyx_t_2); - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_2, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_temp}; - __pyx_t_5 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 313, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - } - __pyx_t_7 = __Pyx_PyUnicode_Concat(__pyx_v_name, __pyx_mstate_global->__pyx_kp_u_rpt); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 313, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_t_5, __pyx_t_7}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 313, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_rpt = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":314 - * inp = os.path.join(os.path.join(dir, 'inp'), name + '.inp') - * rpt = os.path.join(os.path.join(dir, 'temp'), name + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), name + '.opt') # <<<<<<<<<<<<<< - * command = f'{exe} {inp} {rpt} {opt}' - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 314, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 314, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_t_3 = __pyx_t_5; - __Pyx_INCREF(__pyx_t_3); - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 314, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 314, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_4 = __pyx_t_6; - __Pyx_INCREF(__pyx_t_4); - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_4, __pyx_v_dir, __pyx_mstate_global->__pyx_n_u_temp}; - __pyx_t_7 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 314, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - } - __pyx_t_6 = __Pyx_PyUnicode_Concat(__pyx_v_name, __pyx_mstate_global->__pyx_kp_u_opt); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 314, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_8 = 0; - { - PyObject *__pyx_callargs[3] = {__pyx_t_3, __pyx_t_7, __pyx_t_6}; - __pyx_t_1 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_join, __pyx_callargs+__pyx_t_8, (3-__pyx_t_8) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 314, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - } - __pyx_v_opt = __pyx_t_1; - __pyx_t_1 = 0; - - /* "epanet/epanet.py":315 - * rpt = os.path.join(os.path.join(dir, 'temp'), name + '.rpt') - * opt = os.path.join(os.path.join(dir, 'temp'), name + '.opt') - * command = f'{exe} {inp} {rpt} {opt}' # <<<<<<<<<<<<<< - * - * data = {} -*/ - __pyx_t_1 = __Pyx_PyObject_FormatSimple(__pyx_v_exe, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 315, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_1); - __pyx_t_5 = __Pyx_PyObject_FormatSimple(__pyx_v_inp, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 315, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_6 = __Pyx_PyObject_FormatSimple(__pyx_v_rpt, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 315, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = __Pyx_PyObject_FormatSimple(__pyx_v_opt, __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 315, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_9[0] = __pyx_t_1; - __pyx_t_9[1] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_9[2] = __pyx_t_5; - __pyx_t_9[3] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_9[4] = __pyx_t_6; - __pyx_t_9[5] = __pyx_mstate_global->__pyx_kp_u__2; - __pyx_t_9[6] = __pyx_t_7; - __pyx_t_3 = __Pyx_PyUnicode_Join(__pyx_t_9, 7, __Pyx_PyUnicode_GET_LENGTH(__pyx_t_1) + 1 * 3 + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_5) + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_6) + __Pyx_PyUnicode_GET_LENGTH(__pyx_t_7), 127 | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_1) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_5) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_6) | __Pyx_PyUnicode_MAX_CHAR_VALUE(__pyx_t_7)); - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 315, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_v_command = ((PyObject*)__pyx_t_3); - __pyx_t_3 = 0; - - /* "epanet/epanet.py":317 - * command = f'{exe} {inp} {rpt} {opt}' - * - * data = {} # <<<<<<<<<<<<<< - * - * result = os.system(command) -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 317, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_v_data = ((PyObject*)__pyx_t_3); - __pyx_t_3 = 0; - - /* "epanet/epanet.py":319 - * data = {} - * - * result = os.system(command) # <<<<<<<<<<<<<< - * if result != 0: - * data['simulation_result'] = 'failed' -*/ - __pyx_t_7 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_os); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 319, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_system); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 319, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_7); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_7); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_v_command}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 319, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - __pyx_v_result = __pyx_t_3; - __pyx_t_3 = 0; - - /* "epanet/epanet.py":320 - * - * result = os.system(command) - * if result != 0: # <<<<<<<<<<<<<< - * data['simulation_result'] = 'failed' - * else: -*/ - __pyx_t_10 = (__Pyx_PyLong_BoolNeObjC(__pyx_v_result, __pyx_mstate_global->__pyx_int_0, 0, 0)); if (unlikely((__pyx_t_10 < 0))) __PYX_ERR(0, 320, __pyx_L1_error) - if (__pyx_t_10) { - - /* "epanet/epanet.py":321 - * result = os.system(command) - * if result != 0: - * data['simulation_result'] = 'failed' # <<<<<<<<<<<<<< - * else: - * data['simulation_result'] = 'successful' -*/ - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_simulation_result, __pyx_mstate_global->__pyx_n_u_failed) < 0))) __PYX_ERR(0, 321, __pyx_L1_error) - - /* "epanet/epanet.py":320 - * - * result = os.system(command) - * if result != 0: # <<<<<<<<<<<<<< - * data['simulation_result'] = 'failed' - * else: -*/ - goto __pyx_L3; - } - - /* "epanet/epanet.py":323 - * data['simulation_result'] = 'failed' - * else: - * data['simulation_result'] = 'successful' # <<<<<<<<<<<<<< - * # data |= _dump_output(opt) - * data['output'] = dump_output_binary(opt) -*/ - /*else*/ { - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_simulation_result, __pyx_mstate_global->__pyx_n_u_successful) < 0))) __PYX_ERR(0, 323, __pyx_L1_error) - - /* "epanet/epanet.py":325 - * data['simulation_result'] = 'successful' - * # data |= _dump_output(opt) - * data['output'] = dump_output_binary(opt) # <<<<<<<<<<<<<< - * - * data['report'] = dump_report(rpt) -*/ - __pyx_t_5 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_dump_output_binary); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 325, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_7))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_7); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_7); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_7, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_v_opt}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 325, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_output, __pyx_t_3) < 0))) __PYX_ERR(0, 325, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - } - __pyx_L3:; - - /* "epanet/epanet.py":327 - * data['output'] = dump_output_binary(opt) - * - * data['report'] = dump_report(rpt) # <<<<<<<<<<<<<< - * - * return json.dumps(data) -*/ - __pyx_t_7 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_5, __pyx_mstate_global->__pyx_n_u_dump_report); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 327, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_5); - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_5))) { - __pyx_t_7 = PyMethod_GET_SELF(__pyx_t_5); - assert(__pyx_t_7); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_5); - __Pyx_INCREF(__pyx_t_7); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_5, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_7, __pyx_v_rpt}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_5, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_7); __pyx_t_7 = 0; - __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 327, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - if (unlikely((PyDict_SetItem(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_report, __pyx_t_3) < 0))) __PYX_ERR(0, 327, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":329 - * data['report'] = dump_report(rpt) - * - * return json.dumps(data) # <<<<<<<<<<<<<< -*/ - __Pyx_XDECREF(__pyx_r); - __pyx_t_5 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_json_2); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 329, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_7); - __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_7, __pyx_mstate_global->__pyx_n_u_dumps); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 329, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; - __pyx_t_8 = 1; - #if CYTHON_UNPACK_METHODS - if (unlikely(PyMethod_Check(__pyx_t_6))) { - __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6); - assert(__pyx_t_5); - PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_6); - __Pyx_INCREF(__pyx_t_5); - __Pyx_INCREF(__pyx__function); - __Pyx_DECREF_SET(__pyx_t_6, __pyx__function); - __pyx_t_8 = 0; - } - #endif - { - PyObject *__pyx_callargs[2] = {__pyx_t_5, __pyx_v_data}; - __pyx_t_3 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_8, (2-__pyx_t_8) | (__pyx_t_8*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 329, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - } - if (!(likely(PyUnicode_CheckExact(__pyx_t_3))||((__pyx_t_3) == Py_None) || __Pyx_RaiseUnexpectedTypeError("str", __pyx_t_3))) __PYX_ERR(0, 329, __pyx_L1_error) - __pyx_r = ((PyObject*)__pyx_t_3); - __pyx_t_3 = 0; - goto __pyx_L0; - - /* "epanet/epanet.py":308 - * - * - * def run_inp(name: str) -> str: # <<<<<<<<<<<<<< - * dir = os.path.abspath(os.getcwd()) - * -*/ - - /* function exit code */ - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_1); - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_XDECREF(__pyx_t_5); - __Pyx_XDECREF(__pyx_t_6); - __Pyx_XDECREF(__pyx_t_7); - __Pyx_AddTraceback("epanet.epanet.run_inp", __pyx_clineno, __pyx_lineno, __pyx_filename); - __pyx_r = NULL; - __pyx_L0:; - __Pyx_XDECREF(__pyx_v_dir); - __Pyx_XDECREF(__pyx_v_exe); - __Pyx_XDECREF(__pyx_v_inp); - __Pyx_XDECREF(__pyx_v_rpt); - __Pyx_XDECREF(__pyx_v_opt); - __Pyx_XDECREF(__pyx_v_command); - __Pyx_XDECREF(__pyx_v_data); - __Pyx_XDECREF(__pyx_v_result); - __Pyx_XGIVEREF(__pyx_r); - __Pyx_RefNannyFinishContext(); - return __pyx_r; -} -/* #### Code section: module_exttypes ### */ - -static PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; -/* #### Code section: initfunc_declarations ### */ -static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate); /*proto*/ -/* #### Code section: init_module ### */ - -static int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); - /*--- Global init code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); - /*--- Variable export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); - /*--- Function export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); - /*--- Variable import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -#if CYTHON_PEP489_MULTI_PHASE_INIT -static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ -static int __pyx_pymod_exec_epanet(PyObject* module); /*proto*/ -static PyModuleDef_Slot __pyx_moduledef_slots[] = { - {Py_mod_create, (void*)__pyx_pymod_create}, - {Py_mod_exec, (void*)__pyx_pymod_exec_epanet}, - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - {Py_mod_gil, Py_MOD_GIL_USED}, - #endif - #if PY_VERSION_HEX >= 0x030C0000 && CYTHON_USE_MODULE_STATE - {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, - #endif - {0, NULL} -}; -#endif - -#ifdef __cplusplus -namespace { - struct PyModuleDef __pyx_moduledef = - #else - static struct PyModuleDef __pyx_moduledef = - #endif - { - PyModuleDef_HEAD_INIT, - "epanet", - 0, /* m_doc */ - #if CYTHON_USE_MODULE_STATE - sizeof(__pyx_mstatetype), /* m_size */ - #else - (CYTHON_PEP489_MULTI_PHASE_INIT) ? 0 : -1, /* m_size */ - #endif - __pyx_methods /* m_methods */, - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_moduledef_slots, /* m_slots */ - #else - NULL, /* m_reload */ - #endif - #if CYTHON_USE_MODULE_STATE - __pyx_m_traverse, /* m_traverse */ - __pyx_m_clear, /* m_clear */ - NULL /* m_free */ - #else - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ - #endif - }; - #ifdef __cplusplus -} /* anonymous namespace */ -#endif - -/* PyModInitFuncType */ -#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -#else - #ifdef __cplusplus - #define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else - #define __Pyx_PyMODINIT_FUNC PyObject * - #endif -#endif - -__Pyx_PyMODINIT_FUNC PyInit_epanet(void) CYTHON_SMALL_CODE; /*proto*/ -__Pyx_PyMODINIT_FUNC PyInit_epanet(void) -#if CYTHON_PEP489_MULTI_PHASE_INIT -{ - return PyModuleDef_Init(&__pyx_moduledef); -} -/* ModuleCreationPEP489 */ -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x03090000 -static PY_INT64_T __Pyx_GetCurrentInterpreterId(void) { - { - PyObject *module = PyImport_ImportModule("_interpreters"); // 3.13+ I think - if (!module) { - PyErr_Clear(); // just try the 3.8-3.12 version - module = PyImport_ImportModule("_xxsubinterpreters"); - if (!module) goto bad; - } - PyObject *current = PyObject_CallMethod(module, "get_current", NULL); - Py_DECREF(module); - if (!current) goto bad; - if (PyTuple_Check(current)) { - PyObject *new_current = PySequence_GetItem(current, 0); - Py_DECREF(current); - current = new_current; - if (!new_current) goto bad; - } - long long as_c_int = PyLong_AsLongLong(current); - Py_DECREF(current); - return as_c_int; - } - bad: - PySys_WriteStderr("__Pyx_GetCurrentInterpreterId failed. Try setting the C define CYTHON_PEP489_MULTI_PHASE_INIT=0\n"); - return -1; -} -#endif -#if !CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { - static PY_INT64_T main_interpreter_id = -1; -#if CYTHON_COMPILING_IN_GRAAL - PY_INT64_T current_id = PyInterpreterState_GetIDFromThreadState(PyThreadState_Get()); -#elif CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX >= 0x03090000 - PY_INT64_T current_id = PyInterpreterState_GetID(PyInterpreterState_Get()); -#elif CYTHON_COMPILING_IN_LIMITED_API - PY_INT64_T current_id = __Pyx_GetCurrentInterpreterId(); -#else - PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); -#endif - if (unlikely(current_id == -1)) { - return -1; - } - if (main_interpreter_id == -1) { - main_interpreter_id = current_id; - return 0; - } else if (unlikely(main_interpreter_id != current_id)) { - PyErr_SetString( - PyExc_ImportError, - "Interpreter change detected - this module can only be loaded into one interpreter per process."); - return -1; - } - return 0; -} -#endif -static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) -{ - PyObject *value = PyObject_GetAttrString(spec, from_name); - int result = 0; - if (likely(value)) { - if (allow_none || value != Py_None) { - result = PyDict_SetItemString(moddict, to_name, value); - } - Py_DECREF(value); - } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - } else { - result = -1; - } - return result; -} -static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { - PyObject *module = NULL, *moddict, *modname; - CYTHON_UNUSED_VAR(def); - #if !CYTHON_USE_MODULE_STATE - if (__Pyx_check_single_interpreter()) - return NULL; - #endif - if (__pyx_m) - return __Pyx_NewRef(__pyx_m); - modname = PyObject_GetAttrString(spec, "name"); - if (unlikely(!modname)) goto bad; - module = PyModule_NewObject(modname); - Py_DECREF(modname); - if (unlikely(!module)) goto bad; - moddict = PyModule_GetDict(module); - if (unlikely(!moddict)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; - return module; -bad: - Py_XDECREF(module); - return NULL; -} - - -static CYTHON_SMALL_CODE int __pyx_pymod_exec_epanet(PyObject *__pyx_pyinit_module) -#endif -{ - int stringtab_initialized = 0; - #if CYTHON_USE_MODULE_STATE - int pystate_addmodule_run = 0; - #endif - __pyx_mstatetype *__pyx_mstate = NULL; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; - int __pyx_t_4; - int __pyx_t_5; - PyObject *__pyx_t_6 = NULL; - size_t __pyx_t_7; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { - if (__pyx_m == __pyx_pyinit_module) return 0; - PyErr_SetString(PyExc_RuntimeError, "Module 'epanet' has already been imported. Re-initialisation is not supported."); - return -1; - } - #else - if (__pyx_m) return __Pyx_NewRef(__pyx_m); - #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_t_1 = __pyx_pyinit_module; - Py_INCREF(__pyx_t_1); - #else - __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #if CYTHON_USE_MODULE_STATE - { - int add_module_result = __Pyx_State_AddModule(__pyx_t_1, &__pyx_moduledef); - __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "epanet" pseudovariable */ - if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) - pystate_addmodule_run = 1; - } - #else - __pyx_m = __pyx_t_1; - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - PyUnstable_Module_SetGIL(__pyx_m, Py_MOD_GIL_USED); - #endif - __pyx_mstate = __pyx_mstate_global; - CYTHON_UNUSED_VAR(__pyx_t_1); - __pyx_mstate->__pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_mstate->__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) - Py_INCREF(__pyx_mstate->__pyx_d); - __pyx_mstate->__pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_mstate->__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_cython_runtime = __Pyx_PyImport_AddModuleRef("cython_runtime"); if (unlikely(!__pyx_mstate->__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_mstate->__pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /* ImportRefnannyAPI */ - #if CYTHON_REFNANNY -__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); -if (!__Pyx_RefNanny) { - PyErr_Clear(); - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); - if (!__Pyx_RefNanny) - Py_FatalError("failed to import 'refnanny' module"); -} -#endif - -__Pyx_RefNannySetupContext("PyInit_epanet", 0); - if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pxy_PyFrame_Initialize_Offsets - __Pxy_PyFrame_Initialize_Offsets(); - #endif - __pyx_mstate->__pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_mstate->__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pyx_CyFunction_USED - if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_FusedFunction_USED - if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Coroutine_USED - if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Generator_USED - if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_AsyncGen_USED - if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - /*--- Library function declarations ---*/ - /*--- Initialize various global constants etc. ---*/ - if (__Pyx_InitConstants(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - stringtab_initialized = 1; - if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__pyx_module_is_main_epanet__epanet) { - if (PyObject_SetAttr(__pyx_m, __pyx_mstate_global->__pyx_n_u_name_2, __pyx_mstate_global->__pyx_n_u_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - } - { - PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) - if (!PyDict_GetItemString(modules, "epanet.epanet")) { - if (unlikely((PyDict_SetItemString(modules, "epanet.epanet", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) - } - } - /*--- Builtin init code ---*/ - if (__Pyx_InitCachedBuiltins(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Constants init code ---*/ - if (__Pyx_InitCachedConstants(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__Pyx_CreateCodeObjects(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(__pyx_mstate); - (void)__Pyx_modinit_variable_export_code(__pyx_mstate); - (void)__Pyx_modinit_function_export_code(__pyx_mstate); - (void)__Pyx_modinit_type_init_code(__pyx_mstate); - (void)__Pyx_modinit_type_import_code(__pyx_mstate); - (void)__Pyx_modinit_variable_import_code(__pyx_mstate); - (void)__Pyx_modinit_function_import_code(__pyx_mstate); - /*--- Execution code ---*/ - - /* "epanet/epanet.py":1 - * import ctypes # <<<<<<<<<<<<<< - * import platform - * import os -*/ - __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_mstate_global->__pyx_n_u_ctypes, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_ctypes, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":2 - * import ctypes - * import platform # <<<<<<<<<<<<<< - * import os - * import sys -*/ - __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_mstate_global->__pyx_n_u_platform, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 2, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_platform, __pyx_t_2) < 0) __PYX_ERR(0, 2, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":3 - * import ctypes - * import platform - * import os # <<<<<<<<<<<<<< - * import sys - * import json -*/ - __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_mstate_global->__pyx_n_u_os, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 3, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_os, __pyx_t_2) < 0) __PYX_ERR(0, 3, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":4 - * import platform - * import os - * import sys # <<<<<<<<<<<<<< - * import json - * import base64 -*/ - __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_mstate_global->__pyx_n_u_sys, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_sys, __pyx_t_2) < 0) __PYX_ERR(0, 4, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":5 - * import os - * import sys - * import json # <<<<<<<<<<<<<< - * import base64 - * from typing import Any -*/ - __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_mstate_global->__pyx_n_u_json_2, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_json_2, __pyx_t_2) < 0) __PYX_ERR(0, 5, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":6 - * import sys - * import json - * import base64 # <<<<<<<<<<<<<< - * from typing import Any - * sys.path.append("..") -*/ - __pyx_t_2 = __Pyx_ImportDottedModule(__pyx_mstate_global->__pyx_n_u_base64, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_base64, __pyx_t_2) < 0) __PYX_ERR(0, 6, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":7 - * import json - * import base64 - * from typing import Any # <<<<<<<<<<<<<< - * sys.path.append("..") - * from api import project -*/ - __pyx_t_2 = __Pyx_PyList_Pack(1, __pyx_mstate_global->__pyx_n_u_Any); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 7, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_Import(__pyx_mstate_global->__pyx_n_u_typing, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 7, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_Any); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 7, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_Any, __pyx_t_2) < 0) __PYX_ERR(0, 7, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":8 - * import base64 - * from typing import Any - * sys.path.append("..") # <<<<<<<<<<<<<< - * from api import project - * from api import inp_out -*/ - __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_sys); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 8, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_4 = __Pyx_PyObject_Append(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u__4); if (unlikely(__pyx_t_4 == ((int)-1))) __PYX_ERR(0, 8, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":9 - * from typing import Any - * sys.path.append("..") - * from api import project # <<<<<<<<<<<<<< - * from api import inp_out - * -*/ - __pyx_t_2 = __Pyx_PyList_Pack(1, __pyx_mstate_global->__pyx_n_u_project); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __Pyx_Import(__pyx_mstate_global->__pyx_n_u_api, __pyx_t_2, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_2 = __Pyx_ImportFrom(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_project); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_project, __pyx_t_2) < 0) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":10 - * sys.path.append("..") - * from api import project - * from api import inp_out # <<<<<<<<<<<<<< - * - * -*/ - __pyx_t_3 = __Pyx_PyList_Pack(1, __pyx_mstate_global->__pyx_n_u_inp_out); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = __Pyx_Import(__pyx_mstate_global->__pyx_n_u_api, __pyx_t_3, 0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = __Pyx_ImportFrom(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_inp_out); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 10, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_inp_out, __pyx_t_3) < 0) __PYX_ERR(0, 10, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":13 - * - * - * def _verify_platform(): # <<<<<<<<<<<<<< - * _platform = platform.system() - * if _platform != "Windows": -*/ - __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_1_verify_platform, 0, __pyx_mstate_global->__pyx_n_u_verify_platform, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[0])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_verify_platform, __pyx_t_2) < 0) __PYX_ERR(0, 13, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":19 - * - * - * if __name__ == '__main__': # <<<<<<<<<<<<<< - * _verify_platform() - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_name_2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 19, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_5 = (__Pyx_PyUnicode_Equals(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_main, Py_EQ)); if (unlikely((__pyx_t_5 < 0))) __PYX_ERR(0, 19, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (__pyx_t_5) { - - /* "epanet/epanet.py":20 - * - * if __name__ == '__main__': - * _verify_platform() # <<<<<<<<<<<<<< - * - * -*/ - __pyx_t_3 = NULL; - __Pyx_GetModuleGlobalName(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_verify_platform); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 20, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __pyx_t_7 = 1; - { - PyObject *__pyx_callargs[2] = {__pyx_t_3, NULL}; - __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_6, __pyx_callargs+__pyx_t_7, (1-__pyx_t_7) | (__pyx_t_7*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)); - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 20, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - } - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":19 - * - * - * if __name__ == '__main__': # <<<<<<<<<<<<<< - * _verify_platform() - * -*/ - } - - /* "epanet/epanet.py":23 - * - * - * class Output: # <<<<<<<<<<<<<< - * def __init__(self, path: str) -> None: - * self._path = path -*/ - __pyx_t_2 = __Pyx_Py3MetaclassPrepare((PyObject *) NULL, __pyx_mstate_global->__pyx_empty_tuple, __pyx_mstate_global->__pyx_n_u_Output, __pyx_mstate_global->__pyx_n_u_Output, (PyObject *) NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, (PyObject *) NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - - /* "epanet/epanet.py":24 - * - * class Output: - * def __init__(self, path: str) -> None: # <<<<<<<<<<<<<< - * self._path = path - * -*/ - __pyx_t_6 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 24, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_path, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 24, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_n_u_None) < 0) __PYX_ERR(0, 24, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_1__init__, 0, __pyx_mstate_global->__pyx_n_u_Output___init, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[1])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 24, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_6); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_init, __pyx_t_3) < 0) __PYX_ERR(0, 24, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":35 - * - * - * def __del__(self): # <<<<<<<<<<<<<< - * # throw exception in destructor ? :) - * self._check(self._lib.ENR_close(ctypes.byref(self._handle))) -*/ - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_3__del__, 0, __pyx_mstate_global->__pyx_n_u_Output___del, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[2])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 35, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_del, __pyx_t_3) < 0) __PYX_ERR(0, 35, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":40 - * - * - * def _check(self, result): # <<<<<<<<<<<<<< - * if result != 0 and result != 10: - * msg = ctypes.c_char_p() -*/ - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_5_check, 0, __pyx_mstate_global->__pyx_n_u_Output__check, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[3])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 40, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_check, __pyx_t_3) < 0) __PYX_ERR(0, 40, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":53 - * - * - * def version(self) -> int: # <<<<<<<<<<<<<< - * v = ctypes.c_int() - * self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 53, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_n_u_int) < 0) __PYX_ERR(0, 53, __pyx_L1_error) - __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_7version, 0, __pyx_mstate_global->__pyx_n_u_Output_version, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[4])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 53, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_6, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_version, __pyx_t_6) < 0) __PYX_ERR(0, 53, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "epanet/epanet.py":59 - * - * - * def net_size(self) -> dict[str, int]: # <<<<<<<<<<<<<< - * element_count = ctypes.POINTER(ctypes.c_int)() - * length = ctypes.c_int() -*/ - __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 59, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_int) < 0) __PYX_ERR(0, 59, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_9net_size, 0, __pyx_mstate_global->__pyx_n_u_Output_net_size, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[5])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 59, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_6); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_net_size, __pyx_t_3) < 0) __PYX_ERR(0, 59, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":72 - * - * - * def units(self) -> dict[str, str]: # <<<<<<<<<<<<<< - * f_us = ['CFS', 'GPM', 'MGD', 'IMGD', 'AFD', 'LPS', 'LPM', 'MLD', 'CMH', 'CMD'] - * p_us = ['PSI', 'MTR', 'KPA'] -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_str) < 0) __PYX_ERR(0, 72, __pyx_L1_error) - __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_11units, 0, __pyx_mstate_global->__pyx_n_u_Output_units, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[6])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_6, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_units, __pyx_t_6) < 0) __PYX_ERR(0, 72, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "epanet/epanet.py":84 - * - * - * def times(self) -> dict[str, int]: # <<<<<<<<<<<<<< - * ts = [] - * for i in range(1, 5): -*/ - __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 84, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_int) < 0) __PYX_ERR(0, 84, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_13times, 0, __pyx_mstate_global->__pyx_n_u_Output_times, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[7])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 84, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_6); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_times, __pyx_t_3) < 0) __PYX_ERR(0, 84, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":97 - * - * - * def element_name(self) -> dict[str, list[str]]: # <<<<<<<<<<<<<< - * sizes = self.net_size() - * -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 97, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_list_str) < 0) __PYX_ERR(0, 97, __pyx_L1_error) - __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_15element_name, 0, __pyx_mstate_global->__pyx_n_u_Output_element_name, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[8])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 97, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_6, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_element_name, __pyx_t_6) < 0) __PYX_ERR(0, 97, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "epanet/epanet.py":121 - * - * - * def energy_usage(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['pump'] - * usages = [] -*/ - __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 121, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_list_dict_str_Any) < 0) __PYX_ERR(0, 121, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_17energy_usage, 0, __pyx_mstate_global->__pyx_n_u_Output_energy_usage, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[9])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 121, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_6); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_energy_usage, __pyx_t_3) < 0) __PYX_ERR(0, 121, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":140 - * - * - * def reactions(self) -> dict[str, float]: # <<<<<<<<<<<<<< - * values = ctypes.POINTER(ctypes.c_float)() - * length = ctypes.c_int() -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 140, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_float) < 0) __PYX_ERR(0, 140, __pyx_L1_error) - __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_19reactions, 0, __pyx_mstate_global->__pyx_n_u_Output_reactions, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[10])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 140, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_6, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_reactions, __pyx_t_6) < 0) __PYX_ERR(0, 140, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "epanet/epanet.py":153 - * - * - * def node_results(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['node'] - * num_periods = self.times()['num_periods'] -*/ - __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 153, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_list_dict_str_Any) < 0) __PYX_ERR(0, 153, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_21node_results, 0, __pyx_mstate_global->__pyx_n_u_Output_node_results, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[11])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 153, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_6); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_node_results, __pyx_t_3) < 0) __PYX_ERR(0, 153, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":175 - * - * - * def link_results(self) -> list[dict[str, Any]]: # <<<<<<<<<<<<<< - * size = self.net_size()['link'] - * num_periods = self.times()['num_periods'] -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 175, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_list_dict_str_Any) < 0) __PYX_ERR(0, 175, __pyx_L1_error) - __pyx_t_6 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_23link_results, 0, __pyx_mstate_global->__pyx_n_u_Output_link_results, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[12])); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 175, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_6, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_link_results, __pyx_t_6) < 0) __PYX_ERR(0, 175, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - - /* "epanet/epanet.py":204 - * - * - * def dump(self) -> dict[str, Any]: # <<<<<<<<<<<<<< - * data = {} - * data |= { 'version' : self.version() } -*/ - __pyx_t_6 = __Pyx_PyDict_NewPresized(1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 204, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_6); - if (PyDict_SetItem(__pyx_t_6, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_Any) < 0) __PYX_ERR(0, 204, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_6Output_25dump, 0, __pyx_mstate_global->__pyx_n_u_Output_dump, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[13])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 204, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_6); - __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; - if (__Pyx_SetNameInClass(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_dump, __pyx_t_3) < 0) __PYX_ERR(0, 204, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":23 - * - * - * class Output: # <<<<<<<<<<<<<< - * def __init__(self, path: str) -> None: - * self._path = path -*/ - __pyx_t_3 = __Pyx_Py3ClassCreate(((PyObject*)&PyType_Type), __pyx_mstate_global->__pyx_n_u_Output, __pyx_mstate_global->__pyx_empty_tuple, __pyx_t_2, NULL, 0, 0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_Output, __pyx_t_3) < 0) __PYX_ERR(0, 23, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":218 - * - * - * def _dump_output(path: str) -> dict[str, Any]: # <<<<<<<<<<<<<< - * opt = Output(path) - * data = opt.dump() -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 218, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_path, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 218, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_Any) < 0) __PYX_ERR(0, 218, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_3_dump_output, 0, __pyx_mstate_global->__pyx_n_u_dump_output, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[14])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_dump_output, __pyx_t_3) < 0) __PYX_ERR(0, 218, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":226 - * - * - * def dump_output(path: str) -> str: # <<<<<<<<<<<<<< - * data = _dump_output(path) - * return json.dumps(data) -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 226, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 226, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 226, __pyx_L1_error) - __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_5dump_output, 0, __pyx_mstate_global->__pyx_n_u_dump_output_2, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[15])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 226, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_dump_output_2, __pyx_t_2) < 0) __PYX_ERR(0, 226, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":231 - * - * - * def dump_report(path: str) -> str: # <<<<<<<<<<<<<< - * return open(path, 'r').read() - * -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 231, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_path, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 231, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 231, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_7dump_report, 0, __pyx_mstate_global->__pyx_n_u_dump_report, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[16])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 231, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_dump_report, __pyx_t_3) < 0) __PYX_ERR(0, 231, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":235 - * - * - * def dump_output_binary(path: str) -> str: # <<<<<<<<<<<<<< - * with open(path, 'rb') as f: - * data = f.read() -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 235, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_path, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 235, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 235, __pyx_L1_error) - __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_9dump_output_binary, 0, __pyx_mstate_global->__pyx_n_u_dump_output_binary, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[17])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 235, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_dump_output_binary, __pyx_t_2) < 0) __PYX_ERR(0, 235, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":242 - * - * #DingZQ, 2025-02-04, dict[str, Any] - * def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: # <<<<<<<<<<<<<< - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 242, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_name, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 242, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_readable_output, __pyx_mstate_global->__pyx_n_u_bool) < 0) __PYX_ERR(0, 242, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_kp_u_dict_str_Any) < 0) __PYX_ERR(0, 242, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_11run_project_return_dict, 0, __pyx_mstate_global->__pyx_n_u_run_project_return_dict, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[18])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 242, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_3, __pyx_mstate_global->__pyx_tuple[1]); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_run_project_return_dict, __pyx_t_3) < 0) __PYX_ERR(0, 242, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":275 - * - * # original code - * def run_project(name: str, readable_output: bool = False) -> str: # <<<<<<<<<<<<<< - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 275, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_name, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 275, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_readable_output, __pyx_mstate_global->__pyx_n_u_bool) < 0) __PYX_ERR(0, 275, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 275, __pyx_L1_error) - __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_13run_project, 0, __pyx_mstate_global->__pyx_n_u_run_project, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[19])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 275, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_mstate_global->__pyx_tuple[1]); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_2, __pyx_t_3); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_run_project, __pyx_t_2) < 0) __PYX_ERR(0, 275, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet.py":308 - * - * - * def run_inp(name: str) -> str: # <<<<<<<<<<<<<< - * dir = os.path.abspath(os.getcwd()) - * -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 308, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_name, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 308, __pyx_L1_error) - if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_return, __pyx_mstate_global->__pyx_n_u_str) < 0) __PYX_ERR(0, 308, __pyx_L1_error) - __pyx_t_3 = __Pyx_CyFunction_New(&__pyx_mdef_6epanet_6epanet_15run_inp, 0, __pyx_mstate_global->__pyx_n_u_run_inp, NULL, __pyx_mstate_global->__pyx_n_u_epanet_epanet, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[20])); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 308, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - __Pyx_CyFunction_SetAnnotationsDict(__pyx_t_3, __pyx_t_2); - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_run_inp, __pyx_t_3) < 0) __PYX_ERR(0, 308, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /* "epanet/epanet.py":1 - * import ctypes # <<<<<<<<<<<<<< - * import platform - * import os -*/ - __pyx_t_3 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_3); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_test, __pyx_t_3) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - - /*--- Wrapped vars code ---*/ - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_6); - if (__pyx_m) { - if (__pyx_mstate->__pyx_d && stringtab_initialized) { - __Pyx_AddTraceback("init epanet.epanet", __pyx_clineno, __pyx_lineno, __pyx_filename); - } - #if !CYTHON_USE_MODULE_STATE - Py_CLEAR(__pyx_m); - #else - Py_DECREF(__pyx_m); - if (pystate_addmodule_run) { - PyObject *tp, *value, *tb; - PyErr_Fetch(&tp, &value, &tb); - PyState_RemoveModule(&__pyx_moduledef); - PyErr_Restore(tp, value, tb); - } - #endif - } else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ImportError, "init epanet.epanet"); - } - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - #if CYTHON_PEP489_MULTI_PHASE_INIT - return (__pyx_m != NULL) ? 0 : -1; - #else - return __pyx_m; - #endif -} -/* #### Code section: pystring_table ### */ - -typedef struct { - const char *s; -#if 179 <= 65535 - const unsigned short n; -#elif 179 / 2 < INT_MAX - const unsigned int n; -#elif 179 / 2 < LONG_MAX - const unsigned long n; -#else - const Py_ssize_t n; -#endif -#if 1 <= 31 - const unsigned int encoding : 5; -#elif 1 <= 255 - const unsigned char encoding; -#elif 1 <= 65535 - const unsigned short encoding; -#else - const Py_ssize_t encoding; -#endif - const unsigned int is_unicode : 1; - const unsigned int intern : 1; -} __Pyx_StringTabEntry; -static const char * const __pyx_string_tab_encodings[] = { 0 }; -static const __Pyx_StringTabEntry __pyx_string_tab[] = { - {__pyx_k_, sizeof(__pyx_k_), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_ */ - {__pyx_k_2, sizeof(__pyx_k_2), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_2 */ - {__pyx_k_AFD, sizeof(__pyx_k_AFD), 0, 1, 1}, /* PyObject cname: __pyx_n_u_AFD */ - {__pyx_k_Any, sizeof(__pyx_k_Any), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Any */ - {__pyx_k_AssertionError, sizeof(__pyx_k_AssertionError), 0, 1, 1}, /* PyObject cname: __pyx_n_u_AssertionError */ - {__pyx_k_CDLL, sizeof(__pyx_k_CDLL), 0, 1, 1}, /* PyObject cname: __pyx_n_u_CDLL */ - {__pyx_k_CFS, sizeof(__pyx_k_CFS), 0, 1, 1}, /* PyObject cname: __pyx_n_u_CFS */ - {__pyx_k_CLOSED, sizeof(__pyx_k_CLOSED), 0, 1, 1}, /* PyObject cname: __pyx_n_u_CLOSED */ - {__pyx_k_CMD, sizeof(__pyx_k_CMD), 0, 1, 1}, /* PyObject cname: __pyx_n_u_CMD */ - {__pyx_k_CMH, sizeof(__pyx_k_CMH), 0, 1, 1}, /* PyObject cname: __pyx_n_u_CMH */ - {__pyx_k_ENR_checkError, sizeof(__pyx_k_ENR_checkError), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_checkError */ - {__pyx_k_ENR_close, sizeof(__pyx_k_ENR_close), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_close */ - {__pyx_k_ENR_free, sizeof(__pyx_k_ENR_free), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_free */ - {__pyx_k_ENR_getElementName, sizeof(__pyx_k_ENR_getElementName), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getElementName */ - {__pyx_k_ENR_getEnergyUsage, sizeof(__pyx_k_ENR_getEnergyUsage), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getEnergyUsage */ - {__pyx_k_ENR_getLinkResult, sizeof(__pyx_k_ENR_getLinkResult), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getLinkResult */ - {__pyx_k_ENR_getNetReacts, sizeof(__pyx_k_ENR_getNetReacts), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getNetReacts */ - {__pyx_k_ENR_getNetSize, sizeof(__pyx_k_ENR_getNetSize), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getNetSize */ - {__pyx_k_ENR_getNodeResult, sizeof(__pyx_k_ENR_getNodeResult), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getNodeResult */ - {__pyx_k_ENR_getTimes, sizeof(__pyx_k_ENR_getTimes), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getTimes */ - {__pyx_k_ENR_getUnits, sizeof(__pyx_k_ENR_getUnits), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getUnits */ - {__pyx_k_ENR_getVersion, sizeof(__pyx_k_ENR_getVersion), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_getVersion */ - {__pyx_k_ENR_init, sizeof(__pyx_k_ENR_init), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_init */ - {__pyx_k_ENR_open, sizeof(__pyx_k_ENR_open), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ENR_open */ - {__pyx_k_Failed_to_read_project, sizeof(__pyx_k_Failed_to_read_project), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Failed_to_read_project */ - {__pyx_k_GPM, sizeof(__pyx_k_GPM), 0, 1, 1}, /* PyObject cname: __pyx_n_u_GPM */ - {__pyx_k_HOURS, sizeof(__pyx_k_HOURS), 0, 1, 1}, /* PyObject cname: __pyx_n_u_HOURS */ - {__pyx_k_IMGD, sizeof(__pyx_k_IMGD), 0, 1, 1}, /* PyObject cname: __pyx_n_u_IMGD */ - {__pyx_k_KPA, sizeof(__pyx_k_KPA), 0, 1, 1}, /* PyObject cname: __pyx_n_u_KPA */ - {__pyx_k_LPM, sizeof(__pyx_k_LPM), 0, 1, 1}, /* PyObject cname: __pyx_n_u_LPM */ - {__pyx_k_LPS, sizeof(__pyx_k_LPS), 0, 1, 1}, /* PyObject cname: __pyx_n_u_LPS */ - {__pyx_k_MGD, sizeof(__pyx_k_MGD), 0, 1, 1}, /* PyObject cname: __pyx_n_u_MGD */ - {__pyx_k_MGL, sizeof(__pyx_k_MGL), 0, 1, 1}, /* PyObject cname: __pyx_n_u_MGL */ - {__pyx_k_MLD, sizeof(__pyx_k_MLD), 0, 1, 1}, /* PyObject cname: __pyx_n_u_MLD */ - {__pyx_k_MTR, sizeof(__pyx_k_MTR), 0, 1, 1}, /* PyObject cname: __pyx_n_u_MTR */ - {__pyx_k_NONE, sizeof(__pyx_k_NONE), 0, 1, 1}, /* PyObject cname: __pyx_n_u_NONE */ - {__pyx_k_None, sizeof(__pyx_k_None), 0, 1, 1}, /* PyObject cname: __pyx_n_u_None */ - {__pyx_k_Not_found_project, sizeof(__pyx_k_Not_found_project), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Not_found_project */ - {__pyx_k_Note_that_Cython_is_deliberately, sizeof(__pyx_k_Note_that_Cython_is_deliberately), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Note_that_Cython_is_deliberately */ - {__pyx_k_OPEN, sizeof(__pyx_k_OPEN), 0, 1, 1}, /* PyObject cname: __pyx_n_u_OPEN */ - {__pyx_k_Output, sizeof(__pyx_k_Output), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output */ - {__pyx_k_Output___del, sizeof(__pyx_k_Output___del), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output___del */ - {__pyx_k_Output___init, sizeof(__pyx_k_Output___init), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output___init */ - {__pyx_k_Output__check, sizeof(__pyx_k_Output__check), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output__check */ - {__pyx_k_Output_dump, sizeof(__pyx_k_Output_dump), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_dump */ - {__pyx_k_Output_element_name, sizeof(__pyx_k_Output_element_name), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_element_name */ - {__pyx_k_Output_energy_usage, sizeof(__pyx_k_Output_energy_usage), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_energy_usage */ - {__pyx_k_Output_link_results, sizeof(__pyx_k_Output_link_results), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_link_results */ - {__pyx_k_Output_net_size, sizeof(__pyx_k_Output_net_size), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_net_size */ - {__pyx_k_Output_node_results, sizeof(__pyx_k_Output_node_results), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_node_results */ - {__pyx_k_Output_reactions, sizeof(__pyx_k_Output_reactions), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_reactions */ - {__pyx_k_Output_times, sizeof(__pyx_k_Output_times), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_times */ - {__pyx_k_Output_units, sizeof(__pyx_k_Output_units), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_units */ - {__pyx_k_Output_version, sizeof(__pyx_k_Output_version), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Output_version */ - {__pyx_k_POINTER, sizeof(__pyx_k_POINTER), 0, 1, 1}, /* PyObject cname: __pyx_n_u_POINTER */ - {__pyx_k_PRCNT, sizeof(__pyx_k_PRCNT), 0, 1, 1}, /* PyObject cname: __pyx_n_u_PRCNT */ - {__pyx_k_PSI, sizeof(__pyx_k_PSI), 0, 1, 1}, /* PyObject cname: __pyx_n_u_PSI */ - {__pyx_k_Platform, sizeof(__pyx_k_Platform), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Platform */ - {__pyx_k_UGL, sizeof(__pyx_k_UGL), 0, 1, 1}, /* PyObject cname: __pyx_n_u_UGL */ - {__pyx_k_Windows, sizeof(__pyx_k_Windows), 0, 1, 1}, /* PyObject cname: __pyx_n_u_Windows */ - {__pyx_k__2, sizeof(__pyx_k__2), 0, 1, 0}, /* PyObject cname: __pyx_kp_u__2 */ - {__pyx_k__3, sizeof(__pyx_k__3), 0, 1, 0}, /* PyObject cname: __pyx_kp_u__3 */ - {__pyx_k__4, sizeof(__pyx_k__4), 0, 1, 0}, /* PyObject cname: __pyx_kp_u__4 */ - {__pyx_k__5, sizeof(__pyx_k__5), 0, 1, 0}, /* PyObject cname: __pyx_kp_u__5 */ - {__pyx_k_abspath, sizeof(__pyx_k_abspath), 0, 1, 1}, /* PyObject cname: __pyx_n_u_abspath */ - {__pyx_k_add_note, sizeof(__pyx_k_add_note), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_add_note */ - {__pyx_k_api, sizeof(__pyx_k_api), 0, 1, 1}, /* PyObject cname: __pyx_n_u_api */ - {__pyx_k_append, sizeof(__pyx_k_append), 0, 1, 1}, /* PyObject cname: __pyx_n_u_append */ - {__pyx_k_asyncio_coroutines, sizeof(__pyx_k_asyncio_coroutines), 0, 1, 1}, /* PyObject cname: __pyx_n_u_asyncio_coroutines */ - {__pyx_k_attributes, sizeof(__pyx_k_attributes), 0, 1, 1}, /* PyObject cname: __pyx_n_u_attributes */ - {__pyx_k_avg_efficiency, sizeof(__pyx_k_avg_efficiency), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_avg_efficiency */ - {__pyx_k_avg_kW_flow, sizeof(__pyx_k_avg_kW_flow), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_avg_kW_flow */ - {__pyx_k_avg_kwatts, sizeof(__pyx_k_avg_kwatts), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_avg_kwatts */ - {__pyx_k_b64encode, sizeof(__pyx_k_b64encode), 0, 1, 1}, /* PyObject cname: __pyx_n_u_b64encode */ - {__pyx_k_base64, sizeof(__pyx_k_base64), 0, 1, 1}, /* PyObject cname: __pyx_n_u_base64 */ - {__pyx_k_bast64_data, sizeof(__pyx_k_bast64_data), 0, 1, 1}, /* PyObject cname: __pyx_n_u_bast64_data */ - {__pyx_k_bool, sizeof(__pyx_k_bool), 0, 1, 1}, /* PyObject cname: __pyx_n_u_bool */ - {__pyx_k_bulk, sizeof(__pyx_k_bulk), 0, 1, 1}, /* PyObject cname: __pyx_n_u_bulk */ - {__pyx_k_byref, sizeof(__pyx_k_byref), 0, 1, 1}, /* PyObject cname: __pyx_n_u_byref */ - {__pyx_k_c_char_p, sizeof(__pyx_k_c_char_p), 0, 1, 1}, /* PyObject cname: __pyx_n_u_c_char_p */ - {__pyx_k_c_float, sizeof(__pyx_k_c_float), 0, 1, 1}, /* PyObject cname: __pyx_n_u_c_float */ - {__pyx_k_c_int, sizeof(__pyx_k_c_int), 0, 1, 1}, /* PyObject cname: __pyx_n_u_c_int */ - {__pyx_k_c_void_p, sizeof(__pyx_k_c_void_p), 0, 1, 1}, /* PyObject cname: __pyx_n_u_c_void_p */ - {__pyx_k_category, sizeof(__pyx_k_category), 0, 1, 1}, /* PyObject cname: __pyx_n_u_category */ - {__pyx_k_check, sizeof(__pyx_k_check), 0, 1, 1}, /* PyObject cname: __pyx_n_u_check */ - {__pyx_k_class_getitem, sizeof(__pyx_k_class_getitem), 0, 1, 1}, /* PyObject cname: __pyx_n_u_class_getitem */ - {__pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 1, 1}, /* PyObject cname: __pyx_n_u_cline_in_traceback */ - {__pyx_k_code, sizeof(__pyx_k_code), 0, 1, 1}, /* PyObject cname: __pyx_n_u_code */ - {__pyx_k_command, sizeof(__pyx_k_command), 0, 1, 1}, /* PyObject cname: __pyx_n_u_command */ - {__pyx_k_cost_day, sizeof(__pyx_k_cost_day), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cost_day */ - {__pyx_k_ctypes, sizeof(__pyx_k_ctypes), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ctypes */ - {__pyx_k_d, sizeof(__pyx_k_d), 0, 1, 1}, /* PyObject cname: __pyx_n_u_d */ - {__pyx_k_data, sizeof(__pyx_k_data), 0, 1, 1}, /* PyObject cname: __pyx_n_u_data */ - {__pyx_k_db, sizeof(__pyx_k_db), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_db */ - {__pyx_k_db_inp, sizeof(__pyx_k_db_inp), 0, 1, 1}, /* PyObject cname: __pyx_n_u_db_inp */ - {__pyx_k_db_inp_2, sizeof(__pyx_k_db_inp_2), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_db_inp_2 */ - {__pyx_k_decode, sizeof(__pyx_k_decode), 0, 1, 1}, /* PyObject cname: __pyx_n_u_decode */ - {__pyx_k_del, sizeof(__pyx_k_del), 0, 1, 1}, /* PyObject cname: __pyx_n_u_del */ - {__pyx_k_demand, sizeof(__pyx_k_demand), 0, 1, 1}, /* PyObject cname: __pyx_n_u_demand */ - {__pyx_k_dict_str_Any, sizeof(__pyx_k_dict_str_Any), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_dict_str_Any */ - {__pyx_k_dict_str_float, sizeof(__pyx_k_dict_str_float), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_dict_str_float */ - {__pyx_k_dict_str_int, sizeof(__pyx_k_dict_str_int), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_dict_str_int */ - {__pyx_k_dict_str_list_str, sizeof(__pyx_k_dict_str_list_str), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_dict_str_list_str */ - {__pyx_k_dict_str_str, sizeof(__pyx_k_dict_str_str), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_dict_str_str */ - {__pyx_k_dir, sizeof(__pyx_k_dir), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dir */ - {__pyx_k_doc, sizeof(__pyx_k_doc), 0, 1, 1}, /* PyObject cname: __pyx_n_u_doc */ - {__pyx_k_ds, sizeof(__pyx_k_ds), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ds */ - {__pyx_k_dump, sizeof(__pyx_k_dump), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dump */ - {__pyx_k_dump_inp, sizeof(__pyx_k_dump_inp), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dump_inp */ - {__pyx_k_dump_output, sizeof(__pyx_k_dump_output), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dump_output */ - {__pyx_k_dump_output_2, sizeof(__pyx_k_dump_output_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dump_output_2 */ - {__pyx_k_dump_output_binary, sizeof(__pyx_k_dump_output_binary), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dump_output_binary */ - {__pyx_k_dump_report, sizeof(__pyx_k_dump_report), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dump_report */ - {__pyx_k_dumps, sizeof(__pyx_k_dumps), 0, 1, 1}, /* PyObject cname: __pyx_n_u_dumps */ - {__pyx_k_element_count, sizeof(__pyx_k_element_count), 0, 1, 1}, /* PyObject cname: __pyx_n_u_element_count */ - {__pyx_k_element_name, sizeof(__pyx_k_element_name), 0, 1, 1}, /* PyObject cname: __pyx_n_u_element_name */ - {__pyx_k_encode, sizeof(__pyx_k_encode), 0, 1, 1}, /* PyObject cname: __pyx_n_u_encode */ - {__pyx_k_energy_usage, sizeof(__pyx_k_energy_usage), 0, 1, 1}, /* PyObject cname: __pyx_n_u_energy_usage */ - {__pyx_k_enter, sizeof(__pyx_k_enter), 0, 1, 1}, /* PyObject cname: __pyx_n_u_enter */ - {__pyx_k_epanet, sizeof(__pyx_k_epanet), 0, 1, 1}, /* PyObject cname: __pyx_n_u_epanet */ - {__pyx_k_epanet_epanet, sizeof(__pyx_k_epanet_epanet), 0, 1, 1}, /* PyObject cname: __pyx_n_u_epanet_epanet */ - {__pyx_k_epanet_epanet_py, sizeof(__pyx_k_epanet_epanet_py), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_epanet_epanet_py */ - {__pyx_k_epanet_output_dll, sizeof(__pyx_k_epanet_output_dll), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_epanet_output_dll */ - {__pyx_k_error, sizeof(__pyx_k_error), 0, 1, 1}, /* PyObject cname: __pyx_n_u_error */ - {__pyx_k_exe, sizeof(__pyx_k_exe), 0, 1, 1}, /* PyObject cname: __pyx_n_u_exe */ - {__pyx_k_exit, sizeof(__pyx_k_exit), 0, 1, 1}, /* PyObject cname: __pyx_n_u_exit */ - {__pyx_k_f, sizeof(__pyx_k_f), 0, 1, 1}, /* PyObject cname: __pyx_n_u_f */ - {__pyx_k_f_u, sizeof(__pyx_k_f_u), 0, 1, 1}, /* PyObject cname: __pyx_n_u_f_u */ - {__pyx_k_f_us, sizeof(__pyx_k_f_us), 0, 1, 1}, /* PyObject cname: __pyx_n_u_f_us */ - {__pyx_k_failed, sizeof(__pyx_k_failed), 0, 1, 1}, /* PyObject cname: __pyx_n_u_failed */ - {__pyx_k_flow, sizeof(__pyx_k_flow), 0, 1, 1}, /* PyObject cname: __pyx_n_u_flow */ - {__pyx_k_friction, sizeof(__pyx_k_friction), 0, 1, 1}, /* PyObject cname: __pyx_n_u_friction */ - {__pyx_k_func, sizeof(__pyx_k_func), 0, 1, 1}, /* PyObject cname: __pyx_n_u_func */ - {__pyx_k_getcwd, sizeof(__pyx_k_getcwd), 0, 1, 1}, /* PyObject cname: __pyx_n_u_getcwd */ - {__pyx_k_handle, sizeof(__pyx_k_handle), 0, 1, 1}, /* PyObject cname: __pyx_n_u_handle */ - {__pyx_k_have_project, sizeof(__pyx_k_have_project), 0, 1, 1}, /* PyObject cname: __pyx_n_u_have_project */ - {__pyx_k_head, sizeof(__pyx_k_head), 0, 1, 1}, /* PyObject cname: __pyx_n_u_head */ - {__pyx_k_headloss, sizeof(__pyx_k_headloss), 0, 1, 1}, /* PyObject cname: __pyx_n_u_headloss */ - {__pyx_k_i, sizeof(__pyx_k_i), 0, 1, 1}, /* PyObject cname: __pyx_n_u_i */ - {__pyx_k_index, sizeof(__pyx_k_index), 0, 1, 1}, /* PyObject cname: __pyx_n_u_index */ - {__pyx_k_init, sizeof(__pyx_k_init), 0, 1, 1}, /* PyObject cname: __pyx_n_u_init */ - {__pyx_k_initializing, sizeof(__pyx_k_initializing), 0, 1, 1}, /* PyObject cname: __pyx_n_u_initializing */ - {__pyx_k_inp, sizeof(__pyx_k_inp), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_inp */ - {__pyx_k_inp_2, sizeof(__pyx_k_inp_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_inp_2 */ - {__pyx_k_inp_out, sizeof(__pyx_k_inp_out), 0, 1, 1}, /* PyObject cname: __pyx_n_u_inp_out */ - {__pyx_k_input, sizeof(__pyx_k_input), 0, 1, 1}, /* PyObject cname: __pyx_n_u_input */ - {__pyx_k_int, sizeof(__pyx_k_int), 0, 1, 1}, /* PyObject cname: __pyx_n_u_int */ - {__pyx_k_is_coroutine, sizeof(__pyx_k_is_coroutine), 0, 1, 1}, /* PyObject cname: __pyx_n_u_is_coroutine */ - {__pyx_k_j, sizeof(__pyx_k_j), 0, 1, 1}, /* PyObject cname: __pyx_n_u_j */ - {__pyx_k_join, sizeof(__pyx_k_join), 0, 1, 1}, /* PyObject cname: __pyx_n_u_join */ - {__pyx_k_json, sizeof(__pyx_k_json), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_json */ - {__pyx_k_json_2, sizeof(__pyx_k_json_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_json_2 */ - {__pyx_k_k, sizeof(__pyx_k_k), 0, 1, 1}, /* PyObject cname: __pyx_n_u_k */ - {__pyx_k_length, sizeof(__pyx_k_length), 0, 1, 1}, /* PyObject cname: __pyx_n_u_length */ - {__pyx_k_lib, sizeof(__pyx_k_lib), 0, 1, 1}, /* PyObject cname: __pyx_n_u_lib */ - {__pyx_k_link, sizeof(__pyx_k_link), 0, 1, 1}, /* PyObject cname: __pyx_n_u_link */ - {__pyx_k_link_results, sizeof(__pyx_k_link_results), 0, 1, 1}, /* PyObject cname: __pyx_n_u_link_results */ - {__pyx_k_link_type, sizeof(__pyx_k_link_type), 0, 1, 1}, /* PyObject cname: __pyx_n_u_link_type */ - {__pyx_k_links, sizeof(__pyx_k_links), 0, 1, 1}, /* PyObject cname: __pyx_n_u_links */ - {__pyx_k_list_dict_str_Any, sizeof(__pyx_k_list_dict_str_Any), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_list_dict_str_Any */ - {__pyx_k_main, sizeof(__pyx_k_main), 0, 1, 1}, /* PyObject cname: __pyx_n_u_main */ - {__pyx_k_max_kwatts, sizeof(__pyx_k_max_kwatts), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_max_kwatts */ - {__pyx_k_metaclass, sizeof(__pyx_k_metaclass), 0, 1, 1}, /* PyObject cname: __pyx_n_u_metaclass */ - {__pyx_k_module, sizeof(__pyx_k_module), 0, 1, 1}, /* PyObject cname: __pyx_n_u_module */ - {__pyx_k_msg, sizeof(__pyx_k_msg), 0, 1, 1}, /* PyObject cname: __pyx_n_u_msg */ - {__pyx_k_name, sizeof(__pyx_k_name), 0, 1, 1}, /* PyObject cname: __pyx_n_u_name */ - {__pyx_k_name_2, sizeof(__pyx_k_name_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_name_2 */ - {__pyx_k_name_len, sizeof(__pyx_k_name_len), 0, 1, 1}, /* PyObject cname: __pyx_n_u_name_len */ - {__pyx_k_net_size, sizeof(__pyx_k_net_size), 0, 1, 1}, /* PyObject cname: __pyx_n_u_net_size */ - {__pyx_k_node, sizeof(__pyx_k_node), 0, 1, 1}, /* PyObject cname: __pyx_n_u_node */ - {__pyx_k_node_results, sizeof(__pyx_k_node_results), 0, 1, 1}, /* PyObject cname: __pyx_n_u_node_results */ - {__pyx_k_node_type, sizeof(__pyx_k_node_type), 0, 1, 1}, /* PyObject cname: __pyx_n_u_node_type */ - {__pyx_k_nodes, sizeof(__pyx_k_nodes), 0, 1, 1}, /* PyObject cname: __pyx_n_u_nodes */ - {__pyx_k_num_periods, sizeof(__pyx_k_num_periods), 0, 1, 1}, /* PyObject cname: __pyx_n_u_num_periods */ - {__pyx_k_open, sizeof(__pyx_k_open), 0, 1, 1}, /* PyObject cname: __pyx_n_u_open */ - {__pyx_k_opt, sizeof(__pyx_k_opt), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_opt */ - {__pyx_k_opt_2, sizeof(__pyx_k_opt_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_opt_2 */ - {__pyx_k_os, sizeof(__pyx_k_os), 0, 1, 1}, /* PyObject cname: __pyx_n_u_os */ - {__pyx_k_output, sizeof(__pyx_k_output), 0, 1, 1}, /* PyObject cname: __pyx_n_u_output */ - {__pyx_k_output_message, sizeof(__pyx_k_output_message), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_output_message */ - {__pyx_k_p, sizeof(__pyx_k_p), 0, 1, 1}, /* PyObject cname: __pyx_n_u_p */ - {__pyx_k_p_u, sizeof(__pyx_k_p_u), 0, 1, 1}, /* PyObject cname: __pyx_n_u_p_u */ - {__pyx_k_p_us, sizeof(__pyx_k_p_us), 0, 1, 1}, /* PyObject cname: __pyx_n_u_p_us */ - {__pyx_k_path, sizeof(__pyx_k_path), 0, 1, 1}, /* PyObject cname: __pyx_n_u_path */ - {__pyx_k_path_2, sizeof(__pyx_k_path_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_path_2 */ - {__pyx_k_platform, sizeof(__pyx_k_platform), 0, 1, 1}, /* PyObject cname: __pyx_n_u_platform */ - {__pyx_k_platform_2, sizeof(__pyx_k_platform_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_platform_2 */ - {__pyx_k_pop, sizeof(__pyx_k_pop), 0, 1, 1}, /* PyObject cname: __pyx_n_u_pop */ - {__pyx_k_prepare, sizeof(__pyx_k_prepare), 0, 1, 1}, /* PyObject cname: __pyx_n_u_prepare */ - {__pyx_k_pressure, sizeof(__pyx_k_pressure), 0, 1, 1}, /* PyObject cname: __pyx_n_u_pressure */ - {__pyx_k_project, sizeof(__pyx_k_project), 0, 1, 1}, /* PyObject cname: __pyx_n_u_project */ - {__pyx_k_pump, sizeof(__pyx_k_pump), 0, 1, 1}, /* PyObject cname: __pyx_n_u_pump */ - {__pyx_k_q, sizeof(__pyx_k_q), 0, 1, 1}, /* PyObject cname: __pyx_n_u_q */ - {__pyx_k_q_u, sizeof(__pyx_k_q_u), 0, 1, 1}, /* PyObject cname: __pyx_n_u_q_u */ - {__pyx_k_q_us, sizeof(__pyx_k_q_us), 0, 1, 1}, /* PyObject cname: __pyx_n_u_q_us */ - {__pyx_k_quality, sizeof(__pyx_k_quality), 0, 1, 1}, /* PyObject cname: __pyx_n_u_quality */ - {__pyx_k_qualname, sizeof(__pyx_k_qualname), 0, 1, 1}, /* PyObject cname: __pyx_n_u_qualname */ - {__pyx_k_r, sizeof(__pyx_k_r), 0, 1, 1}, /* PyObject cname: __pyx_n_u_r */ - {__pyx_k_range, sizeof(__pyx_k_range), 0, 1, 1}, /* PyObject cname: __pyx_n_u_range */ - {__pyx_k_rb, sizeof(__pyx_k_rb), 0, 1, 1}, /* PyObject cname: __pyx_n_u_rb */ - {__pyx_k_reaction, sizeof(__pyx_k_reaction), 0, 1, 1}, /* PyObject cname: __pyx_n_u_reaction */ - {__pyx_k_reactions, sizeof(__pyx_k_reactions), 0, 1, 1}, /* PyObject cname: __pyx_n_u_reactions */ - {__pyx_k_read, sizeof(__pyx_k_read), 0, 1, 1}, /* PyObject cname: __pyx_n_u_read */ - {__pyx_k_readable_output, sizeof(__pyx_k_readable_output), 0, 1, 1}, /* PyObject cname: __pyx_n_u_readable_output */ - {__pyx_k_report, sizeof(__pyx_k_report), 0, 1, 1}, /* PyObject cname: __pyx_n_u_report */ - {__pyx_k_report_start, sizeof(__pyx_k_report_start), 0, 1, 1}, /* PyObject cname: __pyx_n_u_report_start */ - {__pyx_k_report_step, sizeof(__pyx_k_report_step), 0, 1, 1}, /* PyObject cname: __pyx_n_u_report_step */ - {__pyx_k_result, sizeof(__pyx_k_result), 0, 1, 1}, /* PyObject cname: __pyx_n_u_result */ - {__pyx_k_return, sizeof(__pyx_k_return), 0, 1, 1}, /* PyObject cname: __pyx_n_u_return */ - {__pyx_k_rpt, sizeof(__pyx_k_rpt), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_rpt */ - {__pyx_k_rpt_2, sizeof(__pyx_k_rpt_2), 0, 1, 1}, /* PyObject cname: __pyx_n_u_rpt_2 */ - {__pyx_k_run_inp, sizeof(__pyx_k_run_inp), 0, 1, 1}, /* PyObject cname: __pyx_n_u_run_inp */ - {__pyx_k_run_project, sizeof(__pyx_k_run_project), 0, 1, 1}, /* PyObject cname: __pyx_n_u_run_project */ - {__pyx_k_run_project_return_dict, sizeof(__pyx_k_run_project_return_dict), 0, 1, 1}, /* PyObject cname: __pyx_n_u_run_project_return_dict */ - {__pyx_k_runepanet_exe, sizeof(__pyx_k_runepanet_exe), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_runepanet_exe */ - {__pyx_k_self, sizeof(__pyx_k_self), 0, 1, 1}, /* PyObject cname: __pyx_n_u_self */ - {__pyx_k_setting, sizeof(__pyx_k_setting), 0, 1, 1}, /* PyObject cname: __pyx_n_u_setting */ - {__pyx_k_sim_duration, sizeof(__pyx_k_sim_duration), 0, 1, 1}, /* PyObject cname: __pyx_n_u_sim_duration */ - {__pyx_k_simulation_result, sizeof(__pyx_k_simulation_result), 0, 1, 1}, /* PyObject cname: __pyx_n_u_simulation_result */ - {__pyx_k_size, sizeof(__pyx_k_size), 0, 1, 1}, /* PyObject cname: __pyx_n_u_size */ - {__pyx_k_sizes, sizeof(__pyx_k_sizes), 0, 1, 1}, /* PyObject cname: __pyx_n_u_sizes */ - {__pyx_k_source, sizeof(__pyx_k_source), 0, 1, 1}, /* PyObject cname: __pyx_n_u_source */ - {__pyx_k_spec, sizeof(__pyx_k_spec), 0, 1, 1}, /* PyObject cname: __pyx_n_u_spec */ - {__pyx_k_status, sizeof(__pyx_k_status), 0, 1, 1}, /* PyObject cname: __pyx_n_u_status */ - {__pyx_k_str, sizeof(__pyx_k_str), 0, 1, 1}, /* PyObject cname: __pyx_n_u_str */ - {__pyx_k_successful, sizeof(__pyx_k_successful), 0, 1, 1}, /* PyObject cname: __pyx_n_u_successful */ - {__pyx_k_sys, sizeof(__pyx_k_sys), 0, 1, 1}, /* PyObject cname: __pyx_n_u_sys */ - {__pyx_k_system, sizeof(__pyx_k_system), 0, 1, 1}, /* PyObject cname: __pyx_n_u_system */ - {__pyx_k_t, sizeof(__pyx_k_t), 0, 1, 1}, /* PyObject cname: __pyx_n_u_t */ - {__pyx_k_tank, sizeof(__pyx_k_tank), 0, 1, 1}, /* PyObject cname: __pyx_n_u_tank */ - {__pyx_k_temp, sizeof(__pyx_k_temp), 0, 1, 1}, /* PyObject cname: __pyx_n_u_temp */ - {__pyx_k_test, sizeof(__pyx_k_test), 0, 1, 1}, /* PyObject cname: __pyx_n_u_test */ - {__pyx_k_times, sizeof(__pyx_k_times), 0, 1, 1}, /* PyObject cname: __pyx_n_u_times */ - {__pyx_k_ts, sizeof(__pyx_k_ts), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ts */ - {__pyx_k_typing, sizeof(__pyx_k_typing), 0, 1, 1}, /* PyObject cname: __pyx_n_u_typing */ - {__pyx_k_units, sizeof(__pyx_k_units), 0, 1, 1}, /* PyObject cname: __pyx_n_u_units */ - {__pyx_k_unsupported_not_yet, sizeof(__pyx_k_unsupported_not_yet), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_unsupported_not_yet */ - {__pyx_k_usages, sizeof(__pyx_k_usages), 0, 1, 1}, /* PyObject cname: __pyx_n_u_usages */ - {__pyx_k_utf_8, sizeof(__pyx_k_utf_8), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_utf_8 */ - {__pyx_k_utilization, sizeof(__pyx_k_utilization), 0, 1, 1}, /* PyObject cname: __pyx_n_u_utilization */ - {__pyx_k_v, sizeof(__pyx_k_v), 0, 1, 1}, /* PyObject cname: __pyx_n_u_v */ - {__pyx_k_value, sizeof(__pyx_k_value), 0, 1, 1}, /* PyObject cname: __pyx_n_u_value */ - {__pyx_k_values, sizeof(__pyx_k_values), 0, 1, 1}, /* PyObject cname: __pyx_n_u_values */ - {__pyx_k_valve, sizeof(__pyx_k_valve), 0, 1, 1}, /* PyObject cname: __pyx_n_u_valve */ - {__pyx_k_velocity, sizeof(__pyx_k_velocity), 0, 1, 1}, /* PyObject cname: __pyx_n_u_velocity */ - {__pyx_k_verify_platform, sizeof(__pyx_k_verify_platform), 0, 1, 1}, /* PyObject cname: __pyx_n_u_verify_platform */ - {__pyx_k_version, sizeof(__pyx_k_version), 0, 1, 1}, /* PyObject cname: __pyx_n_u_version */ - {__pyx_k_w, sizeof(__pyx_k_w), 0, 1, 1}, /* PyObject cname: __pyx_n_u_w */ - {__pyx_k_wall, sizeof(__pyx_k_wall), 0, 1, 1}, /* PyObject cname: __pyx_n_u_wall */ - {0, 0, 0, 0, 0} -}; -/* InitStrings.proto */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry const *t, PyObject **target, const char* const* encoding_names); - -/* #### Code section: cached_builtins ### */ - -static int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - __pyx_builtin_AssertionError = __Pyx_GetBuiltinName(__pyx_mstate->__pyx_n_u_AssertionError); if (!__pyx_builtin_AssertionError) __PYX_ERR(0, 44, __pyx_L1_error) - __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_mstate->__pyx_n_u_range); if (!__pyx_builtin_range) __PYX_ERR(0, 66, __pyx_L1_error) - __pyx_builtin_open = __Pyx_GetBuiltinName(__pyx_mstate->__pyx_n_u_open); if (!__pyx_builtin_open) __PYX_ERR(0, 221, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -} -/* #### Code section: cached_constants ### */ - -static int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); - - /* "epanet/epanet.py":221 - * opt = Output(path) - * data = opt.dump() - * with open(path + '.json', 'w') as f: # <<<<<<<<<<<<<< - * json.dump(data, f) - * return data -*/ - __pyx_mstate_global->__pyx_tuple[0] = PyTuple_Pack(3, Py_None, Py_None, Py_None); if (unlikely(!__pyx_mstate_global->__pyx_tuple[0])) __PYX_ERR(0, 221, __pyx_L1_error) - __Pyx_GOTREF(__pyx_mstate_global->__pyx_tuple[0]); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_tuple[0]); - - /* "epanet/epanet.py":242 - * - * #DingZQ, 2025-02-04, dict[str, Any] - * def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: # <<<<<<<<<<<<<< - * if not project.have_project(name): - * raise Exception(f'Not found project [{name}]') -*/ - __pyx_mstate_global->__pyx_tuple[1] = PyTuple_Pack(1, ((PyObject *)Py_False)); if (unlikely(!__pyx_mstate_global->__pyx_tuple[1])) __PYX_ERR(0, 242, __pyx_L1_error) - __Pyx_GOTREF(__pyx_mstate_global->__pyx_tuple[1]); - __Pyx_GIVEREF(__pyx_mstate_global->__pyx_tuple[1]); - __Pyx_RefNannyFinishContext(); - return 0; - __pyx_L1_error:; - __Pyx_RefNannyFinishContext(); - return -1; -} -/* #### Code section: init_constants ### */ - -static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - __pyx_mstate->__pyx_umethod_PyDict_Type_pop.type = (PyObject*)&PyDict_Type; - __pyx_mstate->__pyx_umethod_PyDict_Type_pop.method_name = &__pyx_mstate->__pyx_n_u_pop; - if (__Pyx_InitStrings(__pyx_string_tab, __pyx_mstate->__pyx_string_tab, __pyx_string_tab_encodings) < 0) __PYX_ERR(0, 1, __pyx_L1_error); - __pyx_mstate->__pyx_float_2_0 = PyFloat_FromDouble(2.0); if (unlikely(!__pyx_mstate->__pyx_float_2_0)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_0 = PyLong_FromLong(0); if (unlikely(!__pyx_mstate->__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_1 = PyLong_FromLong(1); if (unlikely(!__pyx_mstate->__pyx_int_1)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_2 = PyLong_FromLong(2); if (unlikely(!__pyx_mstate->__pyx_int_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_3 = PyLong_FromLong(3); if (unlikely(!__pyx_mstate->__pyx_int_3)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_4 = PyLong_FromLong(4); if (unlikely(!__pyx_mstate->__pyx_int_4)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_5 = PyLong_FromLong(5); if (unlikely(!__pyx_mstate->__pyx_int_5)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_6 = PyLong_FromLong(6); if (unlikely(!__pyx_mstate->__pyx_int_6)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_int_10 = PyLong_FromLong(10); if (unlikely(!__pyx_mstate->__pyx_int_10)) __PYX_ERR(0, 1, __pyx_L1_error) - return 0; - __pyx_L1_error:; - return -1; -} -/* #### Code section: init_codeobjects ### */ -\ - typedef struct { - unsigned int argcount : 2; - unsigned int num_posonly_args : 1; - unsigned int num_kwonly_args : 1; - unsigned int nlocals : 4; - unsigned int flags : 10; - unsigned int first_line : 9; - unsigned int line_table_length : 13; - } __Pyx_PyCode_New_function_description; -/* NewCodeObj.proto */ -static PyObject* __Pyx_PyCode_New( - __Pyx_PyCode_New_function_description descr, - PyObject **varnames, - PyObject *filename, - PyObject *funcname, - const char *line_table, - PyObject *tuple_dedup_map -); - - -static int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate) { - PyObject* tuple_dedup_map = PyDict_New(); - if (unlikely(!tuple_dedup_map)) return -1; - { - __Pyx_PyCode_New_function_description descr = {0, 0, 0, 1, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 13, 33}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_platform_2}; - __pyx_mstate_global->__pyx_codeobj_tab[0] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_verify_platform, __pyx_k_q_z_A_iq_q, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[0])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {2, 0, 0, 2, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 24, 113}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_path}; - __pyx_mstate_global->__pyx_codeobj_tab[1] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_init, __pyx_k_XQ_IQ_HF_q_uARwd_A_KvYa_G1D_Yav, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[1])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 1, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 35, 27}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self}; - __pyx_mstate_global->__pyx_codeobj_tab[2] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_del, __pyx_k_A_G1D_Zq_fAT, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[2])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {2, 0, 0, 5, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 40, 111}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_result, __pyx_mstate->__pyx_n_u_msg, __pyx_mstate->__pyx_n_u_code, __pyx_mstate->__pyx_n_u_error}; - __pyx_mstate_global->__pyx_codeobj_tab[3] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_check, __pyx_k_A_7_Rt7_Q_4uO1D_aq_5_1_B_2_6QQTT, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[3])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 2, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 53, 48}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_v}; - __pyx_mstate_global->__pyx_codeobj_tab[4] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_version, __pyx_k_F_G1D__AT_6_q_q, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[4])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 6, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 59, 152}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_element_count, __pyx_mstate->__pyx_n_u_length, __pyx_mstate->__pyx_n_u_category, __pyx_mstate->__pyx_n_u_sizes, __pyx_mstate->__pyx_n_u_i}; - __pyx_mstate_global->__pyx_codeobj_tab[5] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_net_size, __pyx_k_havWA_vQ_G1D__AT_6_qHXX_ddeef_v, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[5])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 10, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 72, 237}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_f_us, __pyx_mstate->__pyx_n_u_p_us, __pyx_mstate->__pyx_n_u_q_us, __pyx_mstate->__pyx_n_u_f, __pyx_mstate->__pyx_n_u_p, __pyx_mstate->__pyx_n_u_q, __pyx_mstate->__pyx_n_u_f_u, __pyx_mstate->__pyx_n_u_p_u, __pyx_mstate->__pyx_n_u_q_u}; - __pyx_mstate_global->__pyx_codeobj_tab[6] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_units, __pyx_k_q_q_wgXWG7_PQ_q_wa_q_wiq_3d_at6, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[6])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 6, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 84, 136}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_ts, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_t, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_category}; - __pyx_mstate_global->__pyx_codeobj_tab[7] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_times, __pyx_k_q_Q_E_as_fAQ_q_E_at_V6_fTZZ_gQa, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[7])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 9, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 97, 329}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_sizes, __pyx_mstate->__pyx_n_u_node_type, __pyx_mstate->__pyx_n_u_nodes, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_name, __pyx_mstate->__pyx_n_u_name_len, __pyx_mstate->__pyx_n_u_link_type, __pyx_mstate->__pyx_n_u_links}; - __pyx_mstate_global->__pyx_codeobj_tab[8] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_element_name, __pyx_k_a_IQ_F_E_as_q_6_vV1_q_E_4AT_fTZ, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[8])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 11, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 121, 274}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_size, __pyx_mstate->__pyx_n_u_usages, __pyx_mstate->__pyx_n_u_category, __pyx_mstate->__pyx_n_u_links, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_index, __pyx_mstate->__pyx_n_u_values, __pyx_mstate->__pyx_n_u_length, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_j}; - __pyx_mstate_global->__pyx_codeobj_tab[9] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_energy_usage, __pyx_k_a_t9Baq_1O_5_NR_a_M_1A_E_as_r_F, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[9])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 6, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 140, 148}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_values, __pyx_mstate->__pyx_n_u_length, __pyx_mstate->__pyx_n_u_category, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_i}; - __pyx_mstate_global->__pyx_codeobj_tab[10] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_reactions, __pyx_k_1_xq_iq_vQ_G1D_at_V6_SYY___a_vW, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[10])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 13, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 153, 274}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_size, __pyx_mstate->__pyx_n_u_num_periods, __pyx_mstate->__pyx_n_u_nodes, __pyx_mstate->__pyx_n_u_category, __pyx_mstate->__pyx_n_u_ds, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_j, __pyx_mstate->__pyx_n_u_values, __pyx_mstate->__pyx_n_u_length, __pyx_mstate->__pyx_n_u_attributes, __pyx_mstate->__pyx_n_u_k}; - __pyx_mstate_global->__pyx_codeobj_tab[11] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_node_results, __pyx_k_a_t9Baq_d_1_M_1A_1Jhl_Q_E_as_r, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[11])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 13, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 175, 339}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_size, __pyx_mstate->__pyx_n_u_num_periods, __pyx_mstate->__pyx_n_u_links, __pyx_mstate->__pyx_n_u_category, __pyx_mstate->__pyx_n_u_ds, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_j, __pyx_mstate->__pyx_n_u_values, __pyx_mstate->__pyx_n_u_length, __pyx_mstate->__pyx_n_u_attributes, __pyx_mstate->__pyx_n_u_k}; - __pyx_mstate_global->__pyx_codeobj_tab[12] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_link_results, __pyx_k_a_t9Baq_d_1_M_1A_1HL_Kz_T_a_Q_E, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[12])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 2, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 204, 118}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_self, __pyx_mstate->__pyx_n_u_data}; - __pyx_mstate_global->__pyx_codeobj_tab[13] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_dump, __pyx_k_a_q_d_t9A_D_a_D_a_4_A_4_A_Ja_4, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[13])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 4, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 218, 56}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_path, __pyx_mstate->__pyx_n_u_opt_2, __pyx_mstate->__pyx_n_u_data, __pyx_mstate->__pyx_n_u_f}; - __pyx_mstate_global->__pyx_codeobj_tab[14] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_dump_output, __pyx_k_xq_3e1_Qe2Yha_E_1, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[14])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 2, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 226, 27}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_path, __pyx_mstate->__pyx_n_u_data}; - __pyx_mstate_global->__pyx_codeobj_tab[15] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_dump_output_2, __pyx_k_ha_q_4vQa, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[15])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 1, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 231, 22}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_path}; - __pyx_mstate_global->__pyx_codeobj_tab[16] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_dump_report, __pyx_k_ha_4q_d_q, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[16])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 4, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 235, 49}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_path, __pyx_mstate->__pyx_n_u_f, __pyx_mstate->__pyx_n_u_data, __pyx_mstate->__pyx_n_u_bast64_data}; - __pyx_mstate_global->__pyx_codeobj_tab[17] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_dump_output_binary, __pyx_k_XQ_QfIQ_q_Q_fJaq_s, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[17])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {2, 0, 0, 12, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 242, 330}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_name, __pyx_mstate->__pyx_n_u_readable_output, __pyx_mstate->__pyx_n_u_dir, __pyx_mstate->__pyx_n_u_db_inp, __pyx_mstate->__pyx_n_u_input, __pyx_mstate->__pyx_n_u_exe, __pyx_mstate->__pyx_n_u_inp_2, __pyx_mstate->__pyx_n_u_rpt_2, __pyx_mstate->__pyx_n_u_opt_2, __pyx_mstate->__pyx_n_u_command, __pyx_mstate->__pyx_n_u_data, __pyx_mstate->__pyx_n_u_result}; - __pyx_mstate_global->__pyx_codeobj_tab[18] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_run_project_return_dict, __pyx_k_88I_t7_q_iq_1_E_G1_RuE_E_auKuBa, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[18])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {2, 0, 0, 12, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 275, 332}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_name, __pyx_mstate->__pyx_n_u_readable_output, __pyx_mstate->__pyx_n_u_dir, __pyx_mstate->__pyx_n_u_db_inp, __pyx_mstate->__pyx_n_u_input, __pyx_mstate->__pyx_n_u_exe, __pyx_mstate->__pyx_n_u_inp_2, __pyx_mstate->__pyx_n_u_rpt_2, __pyx_mstate->__pyx_n_u_opt_2, __pyx_mstate->__pyx_n_u_command, __pyx_mstate->__pyx_n_u_data, __pyx_mstate->__pyx_n_u_result}; - __pyx_mstate_global->__pyx_codeobj_tab[19] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_run_project, __pyx_k_e_Q_t7_q_iq_1_E_G1_RuE_E_auKuBa, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[19])) goto bad; - } - { - __Pyx_PyCode_New_function_description descr = {1, 0, 0, 9, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 308, 234}; - PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_name, __pyx_mstate->__pyx_n_u_dir, __pyx_mstate->__pyx_n_u_exe, __pyx_mstate->__pyx_n_u_inp_2, __pyx_mstate->__pyx_n_u_rpt_2, __pyx_mstate->__pyx_n_u_opt_2, __pyx_mstate->__pyx_n_u_command, __pyx_mstate->__pyx_n_u_data, __pyx_mstate->__pyx_n_u_result}; - __pyx_mstate_global->__pyx_codeobj_tab[20] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_epanet_epanet_py, __pyx_mstate->__pyx_n_u_run_inp, __pyx_k_E_G1_E_ar_e1E_A_E_ar_e1E_b_E_ar, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[20])) goto bad; - } - Py_DECREF(tuple_dedup_map); - return 0; - bad: - Py_DECREF(tuple_dedup_map); - return -1; -} -/* #### Code section: init_globals ### */ - -static int __Pyx_InitGlobals(void) { - /* PythonCompatibility.init */ - if (likely(__Pyx_init_co_variables() == 0)); else - -if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) - - /* AssertionsEnabled.init */ - if (likely(__Pyx_init_assertions_enabled() == 0)); else - -if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) - - /* CachedMethodType.init */ - #if CYTHON_COMPILING_IN_LIMITED_API -{ - PyObject *typesModule=NULL; - typesModule = PyImport_ImportModule("types"); - if (typesModule) { - __pyx_mstate_global->__Pyx_CachedMethodType = PyObject_GetAttrString(typesModule, "MethodType"); - Py_DECREF(typesModule); - } -} // error handling follows -#endif - -if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) - - return 0; - __pyx_L1_error:; - return -1; -} -/* #### Code section: cleanup_globals ### */ -/* #### Code section: cleanup_module ### */ -/* #### Code section: main_method ### */ -/* #### Code section: utility_code_pragmas ### */ -#ifdef _MSC_VER -#pragma warning( push ) -/* Warning 4127: conditional expression is constant - * Cython uses constant conditional expressions to allow in inline functions to be optimized at - * compile-time, so this warning is not useful - */ -#pragma warning( disable : 4127 ) -#endif - - - -/* #### Code section: utility_code_def ### */ - -/* --- Runtime support code --- */ -/* Refnanny */ -#if CYTHON_REFNANNY -static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule(modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, "RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); -end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; -} -#endif - -/* PyErrExceptionMatches */ -#if CYTHON_FAST_THREAD_STATE -static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(tuple); - for (i=0; i= 0x030C00A6 - PyObject *current_exception = tstate->current_exception; - if (unlikely(!current_exception)) return 0; - exc_type = (PyObject*) Py_TYPE(current_exception); - if (exc_type == err) return 1; -#else - exc_type = tstate->curexc_type; - if (exc_type == err) return 1; - if (unlikely(!exc_type)) return 0; -#endif - #if CYTHON_AVOID_BORROWED_REFS - Py_INCREF(exc_type); - #endif - if (unlikely(PyTuple_Check(err))) { - result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); - } else { - result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); - } - #if CYTHON_AVOID_BORROWED_REFS - Py_DECREF(exc_type); - #endif - return result; -} -#endif - -/* PyErrFetchRestore */ -#if CYTHON_FAST_THREAD_STATE -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { -#if PY_VERSION_HEX >= 0x030C00A6 - PyObject *tmp_value; - assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); - if (value) { - #if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) - #endif - PyException_SetTraceback(value, tb); - } - tmp_value = tstate->current_exception; - tstate->current_exception = value; - Py_XDECREF(tmp_value); - Py_XDECREF(type); - Py_XDECREF(tb); -#else - PyObject *tmp_type, *tmp_value, *tmp_tb; - tmp_type = tstate->curexc_type; - tmp_value = tstate->curexc_value; - tmp_tb = tstate->curexc_traceback; - tstate->curexc_type = type; - tstate->curexc_value = value; - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -#endif -} -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { -#if PY_VERSION_HEX >= 0x030C00A6 - PyObject* exc_value; - exc_value = tstate->current_exception; - tstate->current_exception = 0; - *value = exc_value; - *type = NULL; - *tb = NULL; - if (exc_value) { - *type = (PyObject*) Py_TYPE(exc_value); - Py_INCREF(*type); - #if CYTHON_COMPILING_IN_CPYTHON - *tb = ((PyBaseExceptionObject*) exc_value)->traceback; - Py_XINCREF(*tb); - #else - *tb = PyException_GetTraceback(exc_value); - #endif - } -#else - *type = tstate->curexc_type; - *value = tstate->curexc_value; - *tb = tstate->curexc_traceback; - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; -#endif -} -#endif - -/* PyObjectGetAttrStr */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_getattro)) - return tp->tp_getattro(obj, attr_name); - return PyObject_GetAttr(obj, attr_name); -} -#endif - -/* PyObjectGetAttrStrNoError */ -#if __PYX_LIMITED_VERSION_HEX < 0x030d0000 -static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) - __Pyx_PyErr_Clear(); -} -#endif -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { - PyObject *result; -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - (void) PyObject_GetOptionalAttr(obj, attr_name, &result); - return result; -#else -#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { - return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); - } -#endif - result = __Pyx_PyObject_GetAttrStr(obj, attr_name); - if (unlikely(!result)) { - __Pyx_PyObject_GetAttrStr_ClearAttributeError(); - } - return result; -#endif -} - -/* GetBuiltinName */ -static PyObject *__Pyx_GetBuiltinName(PyObject *name) { - PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_mstate_global->__pyx_b, name); - if (unlikely(!result) && !PyErr_Occurred()) { - PyErr_Format(PyExc_NameError, - "name '%U' is not defined", name); - } - return result; -} - -/* TupleAndListFromArray */ -#if !CYTHON_COMPILING_IN_CPYTHON && CYTHON_METH_FASTCALL -static CYTHON_INLINE PyObject * -__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) -{ - PyObject *res; - Py_ssize_t i; - if (n <= 0) { - return __Pyx_NewRef(__pyx_mstate_global->__pyx_empty_tuple); - } - res = PyTuple_New(n); - if (unlikely(res == NULL)) return NULL; - for (i = 0; i < n; i++) { - if (unlikely(__Pyx_PyTuple_SET_ITEM(res, i, src[i]) < 0)) { - Py_DECREF(res); - return NULL; - } - Py_INCREF(src[i]); - } - return res; -} -#elif CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE void __Pyx_copy_object_array(PyObject *const *CYTHON_RESTRICT src, PyObject** CYTHON_RESTRICT dest, Py_ssize_t length) { - PyObject *v; - Py_ssize_t i; - for (i = 0; i < length; i++) { - v = dest[i] = src[i]; - Py_INCREF(v); - } -} -static CYTHON_INLINE PyObject * -__Pyx_PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) -{ - PyObject *res; - if (n <= 0) { - return __Pyx_NewRef(__pyx_mstate_global->__pyx_empty_tuple); - } - res = PyTuple_New(n); - if (unlikely(res == NULL)) return NULL; - __Pyx_copy_object_array(src, ((PyTupleObject*)res)->ob_item, n); - return res; -} -static CYTHON_INLINE PyObject * -__Pyx_PyList_FromArray(PyObject *const *src, Py_ssize_t n) -{ - PyObject *res; - if (n <= 0) { - return PyList_New(0); - } - res = PyList_New(n); - if (unlikely(res == NULL)) return NULL; - __Pyx_copy_object_array(src, ((PyListObject*)res)->ob_item, n); - return res; -} -#endif - -/* BytesEquals */ -static CYTHON_INLINE int __Pyx_PyBytes_Equals(PyObject* s1, PyObject* s2, int equals) { -#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_GRAAL ||\ - !(CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS) - return PyObject_RichCompareBool(s1, s2, equals); -#else - if (s1 == s2) { - return (equals == Py_EQ); - } else if (PyBytes_CheckExact(s1) & PyBytes_CheckExact(s2)) { - const char *ps1, *ps2; - Py_ssize_t length = PyBytes_GET_SIZE(s1); - if (length != PyBytes_GET_SIZE(s2)) - return (equals == Py_NE); - ps1 = PyBytes_AS_STRING(s1); - ps2 = PyBytes_AS_STRING(s2); - if (ps1[0] != ps2[0]) { - return (equals == Py_NE); - } else if (length == 1) { - return (equals == Py_EQ); - } else { - int result; -#if CYTHON_USE_UNICODE_INTERNALS && (PY_VERSION_HEX < 0x030B0000) - Py_hash_t hash1, hash2; - hash1 = ((PyBytesObject*)s1)->ob_shash; - hash2 = ((PyBytesObject*)s2)->ob_shash; - if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { - return (equals == Py_NE); - } -#endif - result = memcmp(ps1, ps2, (size_t)length); - return (equals == Py_EQ) ? (result == 0) : (result != 0); - } - } else if ((s1 == Py_None) & PyBytes_CheckExact(s2)) { - return (equals == Py_NE); - } else if ((s2 == Py_None) & PyBytes_CheckExact(s1)) { - return (equals == Py_NE); - } else { - int result; - PyObject* py_result = PyObject_RichCompare(s1, s2, equals); - if (!py_result) - return -1; - result = __Pyx_PyObject_IsTrue(py_result); - Py_DECREF(py_result); - return result; - } -#endif -} - -/* UnicodeEquals */ -static CYTHON_INLINE int __Pyx_PyUnicode_Equals(PyObject* s1, PyObject* s2, int equals) { -#if CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_GRAAL - return PyObject_RichCompareBool(s1, s2, equals); -#else - int s1_is_unicode, s2_is_unicode; - if (s1 == s2) { - goto return_eq; - } - s1_is_unicode = PyUnicode_CheckExact(s1); - s2_is_unicode = PyUnicode_CheckExact(s2); - if (s1_is_unicode & s2_is_unicode) { - Py_ssize_t length, length2; - int kind; - void *data1, *data2; - #if !CYTHON_COMPILING_IN_LIMITED_API - if (unlikely(__Pyx_PyUnicode_READY(s1) < 0) || unlikely(__Pyx_PyUnicode_READY(s2) < 0)) - return -1; - #endif - length = __Pyx_PyUnicode_GET_LENGTH(s1); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely(length < 0)) return -1; - #endif - length2 = __Pyx_PyUnicode_GET_LENGTH(s2); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely(length2 < 0)) return -1; - #endif - if (length != length2) { - goto return_ne; - } -#if CYTHON_USE_UNICODE_INTERNALS - { - Py_hash_t hash1, hash2; - hash1 = ((PyASCIIObject*)s1)->hash; - hash2 = ((PyASCIIObject*)s2)->hash; - if (hash1 != hash2 && hash1 != -1 && hash2 != -1) { - goto return_ne; - } - } -#endif - kind = __Pyx_PyUnicode_KIND(s1); - if (kind != __Pyx_PyUnicode_KIND(s2)) { - goto return_ne; - } - data1 = __Pyx_PyUnicode_DATA(s1); - data2 = __Pyx_PyUnicode_DATA(s2); - if (__Pyx_PyUnicode_READ(kind, data1, 0) != __Pyx_PyUnicode_READ(kind, data2, 0)) { - goto return_ne; - } else if (length == 1) { - goto return_eq; - } else { - int result = memcmp(data1, data2, (size_t)(length * kind)); - return (equals == Py_EQ) ? (result == 0) : (result != 0); - } - } else if ((s1 == Py_None) & s2_is_unicode) { - goto return_ne; - } else if ((s2 == Py_None) & s1_is_unicode) { - goto return_ne; - } else { - int result; - PyObject* py_result = PyObject_RichCompare(s1, s2, equals); - if (!py_result) - return -1; - result = __Pyx_PyObject_IsTrue(py_result); - Py_DECREF(py_result); - return result; - } -return_eq: - return (equals == Py_EQ); -return_ne: - return (equals == Py_NE); -#endif -} - -/* fastcall */ -#if CYTHON_METH_FASTCALL -static CYTHON_INLINE PyObject * __Pyx_GetKwValue_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues, PyObject *s) -{ - Py_ssize_t i, n = __Pyx_PyTuple_GET_SIZE(kwnames); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely(n == -1)) return NULL; - #endif - for (i = 0; i < n; i++) - { - PyObject *namei = __Pyx_PyTuple_GET_ITEM(kwnames, i); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely(!namei)) return NULL; - #endif - if (s == namei) return kwvalues[i]; - } - for (i = 0; i < n; i++) - { - PyObject *namei = __Pyx_PyTuple_GET_ITEM(kwnames, i); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely(!namei)) return NULL; - #endif - int eq = __Pyx_PyUnicode_Equals(s, namei, Py_EQ); - if (unlikely(eq != 0)) { - if (unlikely(eq < 0)) return NULL; - return kwvalues[i]; - } - } - return NULL; -} -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API -CYTHON_UNUSED static PyObject *__Pyx_KwargsAsDict_FASTCALL(PyObject *kwnames, PyObject *const *kwvalues) { - Py_ssize_t i, nkwargs; - PyObject *dict; -#if !CYTHON_ASSUME_SAFE_SIZE - nkwargs = PyTuple_Size(kwnames); - if (unlikely(nkwargs < 0)) return NULL; -#else - nkwargs = PyTuple_GET_SIZE(kwnames); -#endif - dict = PyDict_New(); - if (unlikely(!dict)) - return NULL; - for (i=0; itp_dict; - return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { - PyObject **dictptr = NULL; - Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; - if (offset) { -#if CYTHON_COMPILING_IN_CPYTHON - dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); -#else - dictptr = _PyObject_GetDictPtr(obj); -#endif - } - return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; -} -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { - PyObject *dict = Py_TYPE(obj)->tp_dict; - if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) - return 0; - return obj_dict_version == __Pyx_get_object_dict_version(obj); -} -#endif - -/* GetModuleGlobalName */ -#if CYTHON_USE_DICT_VERSIONS -static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) -#else -static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) -#endif -{ - PyObject *result; -#if CYTHON_COMPILING_IN_LIMITED_API - if (unlikely(!__pyx_m)) { - if (!PyErr_Occurred()) - PyErr_SetNone(PyExc_NameError); - return NULL; - } - result = PyObject_GetAttr(__pyx_m, name); - if (likely(result)) { - return result; - } - PyErr_Clear(); -#elif CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - if (unlikely(__Pyx_PyDict_GetItemRef(__pyx_mstate_global->__pyx_d, name, &result) == -1)) PyErr_Clear(); - __PYX_UPDATE_DICT_CACHE(__pyx_mstate_global->__pyx_d, result, *dict_cached_value, *dict_version) - if (likely(result)) { - return result; - } -#else - result = _PyDict_GetItem_KnownHash(__pyx_mstate_global->__pyx_d, name, ((PyASCIIObject *) name)->hash); - __PYX_UPDATE_DICT_CACHE(__pyx_mstate_global->__pyx_d, result, *dict_cached_value, *dict_version) - if (likely(result)) { - return __Pyx_NewRef(result); - } - PyErr_Clear(); -#endif - return __Pyx_GetBuiltinName(name); -} - -/* PyFunctionFastCall */ -#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL -static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject *const *args, Py_ssize_t na, - PyObject *globals) { - PyFrameObject *f; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject **fastlocals; - Py_ssize_t i; - PyObject *result; - assert(globals != NULL); - /* XXX Perhaps we should create a specialized - PyFrame_New() that doesn't take locals, but does - take builtins without sanity checking them. - */ - assert(tstate != NULL); - f = PyFrame_New(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - fastlocals = __Pyx_PyFrame_GetLocalsplus(f); - for (i = 0; i < na; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - result = PyEval_EvalFrameEx(f,0); - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - return result; -} -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs) { - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *closure; - PyObject *kwdefs; - PyObject *kwtuple, **k; - PyObject **d; - Py_ssize_t nd; - Py_ssize_t nk; - PyObject *result; - assert(kwargs == NULL || PyDict_Check(kwargs)); - nk = kwargs ? PyDict_Size(kwargs) : 0; - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { - return NULL; - } - if ( - co->co_kwonlyargcount == 0 && - likely(kwargs == NULL || nk == 0) && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { - if (argdefs == NULL && co->co_argcount == nargs) { - result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); - goto done; - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - args = &PyTuple_GET_ITEM(argdefs, 0); - result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); - goto done; - } - } - if (kwargs != NULL) { - Py_ssize_t pos, i; - kwtuple = PyTuple_New(2 * nk); - if (kwtuple == NULL) { - result = NULL; - goto done; - } - k = &PyTuple_GET_ITEM(kwtuple, 0); - pos = i = 0; - while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { - Py_INCREF(k[i]); - Py_INCREF(k[i+1]); - i += 2; - } - nk = i / 2; - } - else { - kwtuple = NULL; - k = NULL; - } - closure = PyFunction_GET_CLOSURE(func); - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, - args, (int)nargs, - k, (int)nk, - d, (int)nd, kwdefs, closure); - Py_XDECREF(kwtuple); -done: - Py_LeaveRecursiveCall(); - return result; -} -#endif - -/* PyObjectCall */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; - ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) - return NULL; - result = (*call)(func, arg, kw); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* PyObjectCallMethO */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { - PyObject *self, *result; - PyCFunction cfunc; - cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); - self = __Pyx_CyOrPyCFunction_GET_SELF(func); - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) - return NULL; - result = cfunc(self, arg); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* PyObjectFastCall */ -#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API -static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs) { - PyObject *argstuple; - PyObject *result = 0; - size_t i; - argstuple = PyTuple_New((Py_ssize_t)nargs); - if (unlikely(!argstuple)) return NULL; - for (i = 0; i < nargs; i++) { - Py_INCREF(args[i]); - if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) != (0)) goto bad; - } - result = __Pyx_PyObject_Call(func, argstuple, kwargs); - bad: - Py_DECREF(argstuple); - return result; -} -#endif -#if CYTHON_VECTORCALL && !CYTHON_COMPILING_IN_LIMITED_API - #if PY_VERSION_HEX < 0x03090000 - #define __Pyx_PyVectorcall_Function(callable) _PyVectorcall_Function(callable) - #elif CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE vectorcallfunc __Pyx_PyVectorcall_Function(PyObject *callable) { - PyTypeObject *tp = Py_TYPE(callable); - #if defined(__Pyx_CyFunction_USED) - if (__Pyx_CyFunction_CheckExact(callable)) { - return __Pyx_CyFunction_func_vectorcall(callable); - } - #endif - if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL)) { - return NULL; - } - assert(PyCallable_Check(callable)); - Py_ssize_t offset = tp->tp_vectorcall_offset; - assert(offset > 0); - vectorcallfunc ptr; - memcpy(&ptr, (char *) callable + offset, sizeof(ptr)); - return ptr; -} - #else - #define __Pyx_PyVectorcall_Function(callable) PyVectorcall_Function(callable) - #endif -#endif -static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject *const *args, size_t _nargs, PyObject *kwargs) { - Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); -#if CYTHON_COMPILING_IN_CPYTHON - if (nargs == 0 && kwargs == NULL) { - if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) - return __Pyx_PyObject_CallMethO(func, NULL); - } - else if (nargs == 1 && kwargs == NULL) { - if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) - return __Pyx_PyObject_CallMethO(func, args[0]); - } -#endif - #if PY_VERSION_HEX < 0x030800B1 - #if CYTHON_FAST_PYCCALL - if (PyCFunction_Check(func)) { - if (kwargs) { - return _PyCFunction_FastCallDict(func, args, nargs, kwargs); - } else { - return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); - } - } - if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { - return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); - } - #endif - #if CYTHON_FAST_PYCALL - if (PyFunction_Check(func)) { - return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); - } - #endif - #endif - if (kwargs == NULL) { - #if CYTHON_VECTORCALL && !CYTHON_COMPILING_IN_LIMITED_API - vectorcallfunc f = __Pyx_PyVectorcall_Function(func); - if (f) { - return f(func, args, _nargs, NULL); - } - #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL - if (__Pyx_CyFunction_CheckExact(func)) { - __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); - if (f) return f(func, args, _nargs, NULL); - } - #elif CYTHON_COMPILING_IN_LIMITED_API && CYTHON_VECTORCALL - return PyObject_Vectorcall(func, args, _nargs, NULL); - #endif - } - if (nargs == 0) { - return __Pyx_PyObject_Call(func, __pyx_mstate_global->__pyx_empty_tuple, kwargs); - } - #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API - return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); - #else - return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); - #endif -} - -/* JoinPyUnicode */ -static PyObject* __Pyx_PyUnicode_Join(PyObject** values, Py_ssize_t value_count, Py_ssize_t result_ulength, - Py_UCS4 max_char) { -#if CYTHON_USE_UNICODE_INTERNALS && CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - PyObject *result_uval; - int result_ukind, kind_shift; - Py_ssize_t i, char_pos; - void *result_udata; - if (max_char > 1114111) max_char = 1114111; - result_uval = PyUnicode_New(result_ulength, max_char); - if (unlikely(!result_uval)) return NULL; - result_ukind = (max_char <= 255) ? PyUnicode_1BYTE_KIND : (max_char <= 65535) ? PyUnicode_2BYTE_KIND : PyUnicode_4BYTE_KIND; - kind_shift = (result_ukind == PyUnicode_4BYTE_KIND) ? 2 : result_ukind - 1; - result_udata = PyUnicode_DATA(result_uval); - assert(kind_shift == 2 || kind_shift == 1 || kind_shift == 0); - if (unlikely((PY_SSIZE_T_MAX >> kind_shift) - result_ulength < 0)) - goto overflow; - char_pos = 0; - for (i=0; i < value_count; i++) { - int ukind; - Py_ssize_t ulength; - void *udata; - PyObject *uval = values[i]; - #if !CYTHON_COMPILING_IN_LIMITED_API - if (__Pyx_PyUnicode_READY(uval) == (-1)) - goto bad; - #endif - ulength = __Pyx_PyUnicode_GET_LENGTH(uval); - #if !CYTHON_ASSUME_SAFE_SIZE - if (unlikely(ulength < 0)) goto bad; - #endif - if (unlikely(!ulength)) - continue; - if (unlikely((PY_SSIZE_T_MAX >> kind_shift) - ulength < char_pos)) - goto overflow; - ukind = __Pyx_PyUnicode_KIND(uval); - udata = __Pyx_PyUnicode_DATA(uval); - if (ukind == result_ukind) { - memcpy((char *)result_udata + (char_pos << kind_shift), udata, (size_t) (ulength << kind_shift)); - } else { - #if PY_VERSION_HEX >= 0x030d0000 - if (unlikely(PyUnicode_CopyCharacters(result_uval, char_pos, uval, 0, ulength) < 0)) goto bad; - #elif CYTHON_COMPILING_IN_CPYTHON || defined(_PyUnicode_FastCopyCharacters) - _PyUnicode_FastCopyCharacters(result_uval, char_pos, uval, 0, ulength); - #else - Py_ssize_t j; - for (j=0; j < ulength; j++) { - Py_UCS4 uchar = __Pyx_PyUnicode_READ(ukind, udata, j); - __Pyx_PyUnicode_WRITE(result_ukind, result_udata, char_pos+j, uchar); - } - #endif - } - char_pos += ulength; - } - return result_uval; -overflow: - PyErr_SetString(PyExc_OverflowError, "join() result is too long for a Python string"); -bad: - Py_DECREF(result_uval); - return NULL; -#else - Py_ssize_t i; - PyObject *result = NULL; - PyObject *value_tuple = PyTuple_New(value_count); - if (unlikely(!value_tuple)) return NULL; - CYTHON_UNUSED_VAR(max_char); - CYTHON_UNUSED_VAR(result_ulength); - for (i=0; i__pyx_empty_unicode, value_tuple); -bad: - Py_DECREF(value_tuple); - return result; -#endif -} - -/* RaiseException */ -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { - PyObject* owned_instance = NULL; - if (tb == Py_None) { - tb = 0; - } else if (tb && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "raise: arg 3 must be a traceback or None"); - goto bad; - } - if (value == Py_None) - value = 0; - if (PyExceptionInstance_Check(type)) { - if (value) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto bad; - } - value = type; - type = (PyObject*) Py_TYPE(value); - } else if (PyExceptionClass_Check(type)) { - PyObject *instance_class = NULL; - if (value && PyExceptionInstance_Check(value)) { - instance_class = (PyObject*) Py_TYPE(value); - if (instance_class != type) { - int is_subclass = PyObject_IsSubclass(instance_class, type); - if (!is_subclass) { - instance_class = NULL; - } else if (unlikely(is_subclass == -1)) { - goto bad; - } else { - type = instance_class; - } - } - } - if (!instance_class) { - PyObject *args; - if (!value) - args = PyTuple_New(0); - else if (PyTuple_Check(value)) { - Py_INCREF(value); - args = value; - } else - args = PyTuple_Pack(1, value); - if (!args) - goto bad; - owned_instance = PyObject_Call(type, args, NULL); - Py_DECREF(args); - if (!owned_instance) - goto bad; - value = owned_instance; - if (!PyExceptionInstance_Check(value)) { - PyErr_Format(PyExc_TypeError, - "calling %R should have returned an instance of " - "BaseException, not %R", - type, Py_TYPE(value)); - goto bad; - } - } - } else { - PyErr_SetString(PyExc_TypeError, - "raise: exception class must be a subclass of BaseException"); - goto bad; - } - if (cause) { - PyObject *fixed_cause; - if (cause == Py_None) { - fixed_cause = NULL; - } else if (PyExceptionClass_Check(cause)) { - fixed_cause = PyObject_CallObject(cause, NULL); - if (fixed_cause == NULL) - goto bad; - } else if (PyExceptionInstance_Check(cause)) { - fixed_cause = cause; - Py_INCREF(fixed_cause); - } else { - PyErr_SetString(PyExc_TypeError, - "exception causes must derive from " - "BaseException"); - goto bad; - } - PyException_SetCause(value, fixed_cause); - } - PyErr_SetObject(type, value); - if (tb) { -#if PY_VERSION_HEX >= 0x030C00A6 - PyException_SetTraceback(value, tb); -#elif CYTHON_FAST_THREAD_STATE - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject* tmp_tb = tstate->curexc_traceback; - if (tb != tmp_tb) { - Py_INCREF(tb); - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_tb); - } -#else - PyObject *tmp_type, *tmp_value, *tmp_tb; - PyErr_Fetch(&tmp_type, &tmp_value, &tmp_tb); - Py_INCREF(tb); - PyErr_Restore(tmp_type, tmp_value, tb); - Py_XDECREF(tmp_tb); -#endif - } -bad: - Py_XDECREF(owned_instance); - return; -} - -/* RaiseDoubleKeywords */ -static void __Pyx_RaiseDoubleKeywordsError( - const char* func_name, - PyObject* kw_name) -{ - PyErr_Format(PyExc_TypeError, - "%s() got multiple values for keyword argument '%U'", func_name, kw_name); -} - -/* UnpackUnboundCMethod */ -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030C0000 -static PyObject *__Pyx_SelflessCall(PyObject *method, PyObject *args, PyObject *kwargs) { - PyObject *result; - PyObject *selfless_args = PyTuple_GetSlice(args, 1, PyTuple_Size(args)); - if (unlikely(!selfless_args)) return NULL; - result = PyObject_Call(method, selfless_args, kwargs); - Py_DECREF(selfless_args); - return result; -} -#else -static PyObject *__Pyx_SelflessCall(PyObject *method, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { - return -#if PY_VERSION_HEX < 0x03090000 - _PyObject_Vectorcall -#else - PyObject_Vectorcall -#endif - (method, args ? args+1 : NULL, nargs ? (size_t) nargs-1 : 0, kwnames); -} -#endif -static PyMethodDef __Pyx_UnboundCMethod_Def = { - "CythonUnboundCMethod", - __PYX_REINTERPRET_FUNCION(PyCFunction, __Pyx_SelflessCall), -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030C0000 - METH_VARARGS | METH_KEYWORDS, -#else - METH_FASTCALL | METH_KEYWORDS, -#endif - NULL -}; -static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) { - PyObject *method, *result=NULL; - method = __Pyx_PyObject_GetAttrStr(target->type, *target->method_name); - if (unlikely(!method)) - return -1; - result = method; -#if CYTHON_COMPILING_IN_CPYTHON - if (likely(__Pyx_TypeCheck(method, &PyMethodDescr_Type))) - { - PyMethodDescrObject *descr = (PyMethodDescrObject*) method; - target->func = descr->d_method->ml_meth; - target->flag = descr->d_method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_STACKLESS); - } else -#endif -#if CYTHON_COMPILING_IN_PYPY -#else - if (PyCFunction_Check(method)) -#endif - { - PyObject *self; - int self_found; -#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_PYPY - self = PyObject_GetAttrString(method, "__self__"); - if (!self) { - PyErr_Clear(); - } -#else - self = PyCFunction_GET_SELF(method); -#endif - self_found = (self && self != Py_None); -#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_COMPILING_IN_PYPY - Py_XDECREF(self); -#endif - if (self_found) { - PyObject *unbound_method = PyCFunction_New(&__Pyx_UnboundCMethod_Def, method); - if (unlikely(!unbound_method)) return -1; - Py_DECREF(method); - result = unbound_method; - } - } -#if !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - if (unlikely(target->method)) { - Py_DECREF(result); - } else -#endif - target->method = result; - return 0; -} - -/* CallUnboundCMethod2 */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject *__Pyx_CallUnboundCMethod2(__Pyx_CachedCFunction *cfunc, PyObject *self, PyObject *arg1, PyObject *arg2) { - int was_initialized = __Pyx_CachedCFunction_GetAndSetInitializing(cfunc); - if (likely(was_initialized == 2 && cfunc->func)) { - PyObject *args[2] = {arg1, arg2}; - if (cfunc->flag == METH_FASTCALL) { - return __Pyx_CallCFunctionFast(cfunc, self, args, 2); - } - if (cfunc->flag == (METH_FASTCALL | METH_KEYWORDS)) - return __Pyx_CallCFunctionFastWithKeywords(cfunc, self, args, 2, NULL); - } -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - else if (unlikely(was_initialized == 1)) { - __Pyx_CachedCFunction tmp_cfunc = { -#ifndef __cplusplus - 0 -#endif - }; - tmp_cfunc.type = cfunc->type; - tmp_cfunc.method_name = cfunc->method_name; - return __Pyx__CallUnboundCMethod2(&tmp_cfunc, self, arg1, arg2); - } -#endif - PyObject *result = __Pyx__CallUnboundCMethod2(cfunc, self, arg1, arg2); - __Pyx_CachedCFunction_SetFinishedInitializing(cfunc); - return result; -} -#endif -static PyObject* __Pyx__CallUnboundCMethod2(__Pyx_CachedCFunction* cfunc, PyObject* self, PyObject* arg1, PyObject* arg2){ - if (unlikely(!cfunc->func && !cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL; -#if CYTHON_COMPILING_IN_CPYTHON - if (cfunc->func && (cfunc->flag & METH_VARARGS)) { - PyObject *result = NULL; - PyObject *args = PyTuple_New(2); - if (unlikely(!args)) return NULL; - Py_INCREF(arg1); - PyTuple_SET_ITEM(args, 0, arg1); - Py_INCREF(arg2); - PyTuple_SET_ITEM(args, 1, arg2); - if (cfunc->flag & METH_KEYWORDS) - result = __Pyx_CallCFunctionWithKeywords(cfunc, self, args, NULL); - else - result = __Pyx_CallCFunction(cfunc, self, args); - Py_DECREF(args); - return result; - } -#endif - { - PyObject *args[4] = {NULL, self, arg1, arg2}; - return __Pyx_PyObject_FastCall(cfunc->method, args+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); - } -} - -/* ParseKeywords */ -static int __Pyx_ValidateDuplicatePosArgs( - PyObject *kwds, - PyObject ** const argnames[], - PyObject ** const *first_kw_arg, - const char* function_name) -{ - PyObject ** const *name = argnames; - while (name != first_kw_arg) { - PyObject *key = **name; - int found = PyDict_Contains(kwds, key); - if (unlikely(found)) { - if (found == 1) __Pyx_RaiseDoubleKeywordsError(function_name, key); - goto bad; - } - name++; - } - return 0; -bad: - return -1; -} -#if CYTHON_USE_UNICODE_INTERNALS -static CYTHON_INLINE int __Pyx_UnicodeKeywordsEqual(PyObject *s1, PyObject *s2) { - int kind; - Py_ssize_t len = PyUnicode_GET_LENGTH(s1); - if (len != PyUnicode_GET_LENGTH(s2)) return 0; - kind = PyUnicode_KIND(s1); - if (kind != PyUnicode_KIND(s2)) return 0; - const void *data1 = PyUnicode_DATA(s1); - const void *data2 = PyUnicode_DATA(s2); - return (memcmp(data1, data2, (size_t) len * (size_t) kind) == 0); -} -#endif -static int __Pyx_MatchKeywordArg_str( - PyObject *key, - PyObject ** const argnames[], - PyObject ** const *first_kw_arg, - size_t *index_found, - const char *function_name) -{ - PyObject ** const *name; - #if CYTHON_USE_UNICODE_INTERNALS - Py_hash_t key_hash = ((PyASCIIObject*)key)->hash; - if (unlikely(key_hash == -1)) { - key_hash = PyObject_Hash(key); - if (unlikely(key_hash == -1)) - goto bad; - } - #endif - name = first_kw_arg; - while (*name) { - PyObject *name_str = **name; - #if CYTHON_USE_UNICODE_INTERNALS - if (key_hash == ((PyASCIIObject*)name_str)->hash && __Pyx_UnicodeKeywordsEqual(name_str, key)) { - *index_found = (size_t) (name - argnames); - return 1; - } - #else - #if CYTHON_ASSUME_SAFE_SIZE - if (PyUnicode_GET_LENGTH(name_str) == PyUnicode_GET_LENGTH(key)) - #endif - { - int cmp = PyUnicode_Compare(name_str, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; - if (cmp == 0) { - *index_found = (size_t) (name - argnames); - return 1; - } - } - #endif - name++; - } - name = argnames; - while (name != first_kw_arg) { - PyObject *name_str = **name; - #if CYTHON_USE_UNICODE_INTERNALS - if (unlikely(key_hash == ((PyASCIIObject*)name_str)->hash)) { - if (__Pyx_UnicodeKeywordsEqual(name_str, key)) - goto arg_passed_twice; - } - #else - #if CYTHON_ASSUME_SAFE_SIZE - if (PyUnicode_GET_LENGTH(name_str) == PyUnicode_GET_LENGTH(key)) - #endif - { - if (unlikely(name_str == key)) goto arg_passed_twice; - int cmp = PyUnicode_Compare(name_str, key); - if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; - if (cmp == 0) goto arg_passed_twice; - } - #endif - name++; - } - return 0; -arg_passed_twice: - __Pyx_RaiseDoubleKeywordsError(function_name, key); - goto bad; -bad: - return -1; -} -static int __Pyx_MatchKeywordArg_nostr( - PyObject *key, - PyObject ** const argnames[], - PyObject ** const *first_kw_arg, - size_t *index_found, - const char *function_name) -{ - PyObject ** const *name; - if (unlikely(!PyUnicode_Check(key))) goto invalid_keyword_type; - name = first_kw_arg; - while (*name) { - int cmp = PyObject_RichCompareBool(**name, key, Py_EQ); - if (cmp == 1) { - *index_found = (size_t) (name - argnames); - return 1; - } - if (unlikely(cmp == -1)) goto bad; - name++; - } - name = argnames; - while (name != first_kw_arg) { - int cmp = PyObject_RichCompareBool(**name, key, Py_EQ); - if (unlikely(cmp != 0)) { - if (cmp == 1) goto arg_passed_twice; - else goto bad; - } - name++; - } - return 0; -arg_passed_twice: - __Pyx_RaiseDoubleKeywordsError(function_name, key); - goto bad; -invalid_keyword_type: - PyErr_Format(PyExc_TypeError, - "%.200s() keywords must be strings", function_name); - goto bad; -bad: - return -1; -} -static CYTHON_INLINE int __Pyx_MatchKeywordArg( - PyObject *key, - PyObject ** const argnames[], - PyObject ** const *first_kw_arg, - size_t *index_found, - const char *function_name) -{ - return likely(PyUnicode_CheckExact(key)) ? - __Pyx_MatchKeywordArg_str(key, argnames, first_kw_arg, index_found, function_name) : - __Pyx_MatchKeywordArg_nostr(key, argnames, first_kw_arg, index_found, function_name); -} -static void __Pyx_RejectUnknownKeyword( - PyObject *kwds, - PyObject ** const argnames[], - PyObject ** const *first_kw_arg, - const char *function_name) -{ - Py_ssize_t pos = 0; - PyObject *key = NULL; - __Pyx_BEGIN_CRITICAL_SECTION(kwds); - while (PyDict_Next(kwds, &pos, &key, NULL)) { - PyObject** const *name = first_kw_arg; - while (*name && (**name != key)) name++; - if (!*name) { - #if CYTHON_AVOID_BORROWED_REFS - Py_INCREF(key); - #endif - size_t index_found = 0; - int cmp = __Pyx_MatchKeywordArg(key, argnames, first_kw_arg, &index_found, function_name); - if (cmp != 1) { - if (cmp == 0) { - PyErr_Format(PyExc_TypeError, - "%s() got an unexpected keyword argument '%U'", - function_name, key); - } - #if CYTHON_AVOID_BORROWED_REFS - Py_DECREF(key); - #endif - break; - } - #if CYTHON_AVOID_BORROWED_REFS - Py_DECREF(key); - #endif - } - } - __Pyx_END_CRITICAL_SECTION(); - assert(PyErr_Occurred()); -} -static int __Pyx_ParseKeywordDict( - PyObject *kwds, - PyObject ** const argnames[], - PyObject *values[], - Py_ssize_t num_pos_args, - Py_ssize_t num_kwargs, - const char* function_name, - int ignore_unknown_kwargs) -{ - PyObject** const *name; - PyObject** const *first_kw_arg = argnames + num_pos_args; - Py_ssize_t extracted = 0; - if (unlikely(!PyArg_ValidateKeywordArguments(kwds))) return -1; - name = first_kw_arg; - while (*name && num_kwargs > extracted) { - PyObject * key = **name; - PyObject *value; - int found = 0; - #if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - found = PyDict_GetItemRef(kwds, key, &value); - #else - value = PyDict_GetItemWithError(kwds, key); - if (value) { - Py_INCREF(value); - found = 1; - } else { - if (unlikely(PyErr_Occurred())) goto bad; - } - #endif - if (found) { - if (unlikely(found < 0)) goto bad; - values[name-argnames] = value; - extracted++; - } - name++; - } - if (num_kwargs > extracted) { - if (ignore_unknown_kwargs) { - if (unlikely(__Pyx_ValidateDuplicatePosArgs(kwds, argnames, first_kw_arg, function_name) == -1)) - goto bad; - } else { - __Pyx_RejectUnknownKeyword(kwds, argnames, first_kw_arg, function_name); - goto bad; - } - } - return 0; -bad: - return -1; -} -static int __Pyx_ParseKeywordDictToDict( - PyObject *kwds, - PyObject ** const argnames[], - PyObject *kwds2, - PyObject *values[], - Py_ssize_t num_pos_args, - const char* function_name) -{ - PyObject** const *name; - PyObject** const *first_kw_arg = argnames + num_pos_args; - Py_ssize_t len; - if (unlikely(!PyArg_ValidateKeywordArguments(kwds))) return -1; - if (PyDict_Update(kwds2, kwds) < 0) goto bad; - name = first_kw_arg; - while (*name) { - PyObject *key = **name; - PyObject *value; -#if !CYTHON_COMPILING_IN_LIMITED_API && (PY_VERSION_HEX >= 0x030d00A2 || defined(PyDict_Pop)) - int found = PyDict_Pop(kwds2, key, &value); - if (found) { - if (unlikely(found < 0)) goto bad; - values[name-argnames] = value; - } -#elif __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - int found = PyDict_GetItemRef(kwds2, key, &value); - if (found) { - if (unlikely(found < 0)) goto bad; - values[name-argnames] = value; - if (unlikely(PyDict_DelItem(kwds2, key) < 0)) goto bad; - } -#else - #if CYTHON_COMPILING_IN_CPYTHON - value = _PyDict_Pop(kwds2, key, kwds2); - #else - value = __Pyx_CallUnboundCMethod2(&__pyx_mstate_global->__pyx_umethod_PyDict_Type_pop, kwds2, key, kwds2); - #endif - if (value == kwds2) { - Py_DECREF(value); - } else { - if (unlikely(!value)) goto bad; - values[name-argnames] = value; - } -#endif - name++; - } - len = PyDict_Size(kwds2); - if (len > 0) { - return __Pyx_ValidateDuplicatePosArgs(kwds, argnames, first_kw_arg, function_name); - } else if (unlikely(len == -1)) { - goto bad; - } - return 0; -bad: - return -1; -} -static int __Pyx_ParseKeywordsTuple( - PyObject *kwds, - PyObject * const *kwvalues, - PyObject ** const argnames[], - PyObject *kwds2, - PyObject *values[], - Py_ssize_t num_pos_args, - Py_ssize_t num_kwargs, - const char* function_name, - int ignore_unknown_kwargs) -{ - PyObject *key = NULL; - PyObject** const * name; - PyObject** const *first_kw_arg = argnames + num_pos_args; - for (Py_ssize_t pos = 0; pos < num_kwargs; pos++) { -#if CYTHON_AVOID_BORROWED_REFS - key = __Pyx_PySequence_ITEM(kwds, pos); -#else - key = __Pyx_PyTuple_GET_ITEM(kwds, pos); -#endif -#if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely(!key)) goto bad; -#endif - name = first_kw_arg; - while (*name && (**name != key)) name++; - if (*name) { - PyObject *value = kwvalues[pos]; - values[name-argnames] = __Pyx_NewRef(value); - } else { - size_t index_found = 0; - int cmp = __Pyx_MatchKeywordArg(key, argnames, first_kw_arg, &index_found, function_name); - if (cmp == 1) { - PyObject *value = kwvalues[pos]; - values[index_found] = __Pyx_NewRef(value); - } else { - if (unlikely(cmp == -1)) goto bad; - if (kwds2) { - PyObject *value = kwvalues[pos]; - if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; - } else if (!ignore_unknown_kwargs) { - goto invalid_keyword; - } - } - } - #if CYTHON_AVOID_BORROWED_REFS - Py_DECREF(key); - key = NULL; - #endif - } - return 0; -invalid_keyword: - PyErr_Format(PyExc_TypeError, - "%s() got an unexpected keyword argument '%U'", - function_name, key); - goto bad; -bad: - #if CYTHON_AVOID_BORROWED_REFS - Py_XDECREF(key); - #endif - return -1; -} -static int __Pyx_ParseKeywords( - PyObject *kwds, - PyObject * const *kwvalues, - PyObject ** const argnames[], - PyObject *kwds2, - PyObject *values[], - Py_ssize_t num_pos_args, - Py_ssize_t num_kwargs, - const char* function_name, - int ignore_unknown_kwargs) -{ - if (CYTHON_METH_FASTCALL && likely(PyTuple_Check(kwds))) - return __Pyx_ParseKeywordsTuple(kwds, kwvalues, argnames, kwds2, values, num_pos_args, num_kwargs, function_name, ignore_unknown_kwargs); - else if (kwds2) - return __Pyx_ParseKeywordDictToDict(kwds, argnames, kwds2, values, num_pos_args, function_name); - else - return __Pyx_ParseKeywordDict(kwds, argnames, values, num_pos_args, num_kwargs, function_name, ignore_unknown_kwargs); -} - -/* RaiseArgTupleInvalid */ -static void __Pyx_RaiseArgtupleInvalid( - const char* func_name, - int exact, - Py_ssize_t num_min, - Py_ssize_t num_max, - Py_ssize_t num_found) -{ - Py_ssize_t num_expected; - const char *more_or_less; - if (num_found < num_min) { - num_expected = num_min; - more_or_less = "at least"; - } else { - num_expected = num_max; - more_or_less = "at most"; - } - if (exact) { - more_or_less = "exactly"; - } - PyErr_Format(PyExc_TypeError, - "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", - func_name, more_or_less, num_expected, - (num_expected == 1) ? "" : "s", num_found); -} - -/* ArgTypeTest */ -static int __Pyx__ArgTypeTest(PyObject *obj, PyTypeObject *type, const char *name, int exact) -{ - __Pyx_TypeName type_name; - __Pyx_TypeName obj_type_name; - PyObject *extra_info = __pyx_mstate_global->__pyx_empty_unicode; - int from_annotation_subclass = 0; - if (unlikely(!type)) { - PyErr_SetString(PyExc_SystemError, "Missing type object"); - return 0; - } - else if (!exact) { - if (likely(__Pyx_TypeCheck(obj, type))) return 1; - } else if (exact == 2) { - if (__Pyx_TypeCheck(obj, type)) { - from_annotation_subclass = 1; - extra_info = __pyx_mstate_global->__pyx_kp_u_Note_that_Cython_is_deliberately; - } - } - type_name = __Pyx_PyType_GetFullyQualifiedName(type); - obj_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(obj)); - PyErr_Format(PyExc_TypeError, - "Argument '%.200s' has incorrect type (expected " __Pyx_FMT_TYPENAME - ", got " __Pyx_FMT_TYPENAME ")" -#if __PYX_LIMITED_VERSION_HEX < 0x030C0000 - "%s%U" -#endif - , name, type_name, obj_type_name -#if __PYX_LIMITED_VERSION_HEX < 0x030C0000 - , (from_annotation_subclass ? ". " : ""), extra_info -#endif - ); -#if __PYX_LIMITED_VERSION_HEX >= 0x030C0000 - if (exact == 2 && from_annotation_subclass) { - PyObject *res; - PyObject *vargs[2]; - vargs[0] = PyErr_GetRaisedException(); - vargs[1] = extra_info; - res = PyObject_VectorcallMethod(__pyx_mstate_global->__pyx_kp_u_add_note, vargs, 2, NULL); - Py_XDECREF(res); - PyErr_SetRaisedException(vargs[0]); - } -#endif - __Pyx_DECREF_TypeName(type_name); - __Pyx_DECREF_TypeName(obj_type_name); - return 0; -} - -/* PyObjectSetAttrStr */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE int __Pyx_PyObject_SetAttrStr(PyObject* obj, PyObject* attr_name, PyObject* value) { - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_setattro)) - return tp->tp_setattro(obj, attr_name, value); - return PyObject_SetAttr(obj, attr_name, value); -} -#endif - -/* PyObjectFastCallMethod */ -#if !CYTHON_VECTORCALL || PY_VERSION_HEX < 0x03090000 -static PyObject *__Pyx_PyObject_FastCallMethod(PyObject *name, PyObject *const *args, size_t nargsf) { - PyObject *result; - PyObject *attr = PyObject_GetAttr(args[0], name); - if (unlikely(!attr)) - return NULL; - result = __Pyx_PyObject_FastCall(attr, args+1, nargsf - 1); - Py_DECREF(attr); - return result; -} -#endif - -/* PyLongCompare */ -static CYTHON_INLINE int __Pyx_PyLong_BoolNeObjC(PyObject *op1, PyObject *op2, long intval, long inplace) { - CYTHON_MAYBE_UNUSED_VAR(intval); - CYTHON_UNUSED_VAR(inplace); - if (op1 == op2) { - return 0; - } - #if CYTHON_USE_PYLONG_INTERNALS - if (likely(PyLong_CheckExact(op1))) { - int unequal; - unsigned long uintval; - Py_ssize_t size = __Pyx_PyLong_DigitCount(op1); - const digit* digits = __Pyx_PyLong_Digits(op1); - if (intval == 0) { - return (__Pyx_PyLong_IsZero(op1) != 1); - } else if (intval < 0) { - if (__Pyx_PyLong_IsNonNeg(op1)) - return 1; - intval = -intval; - } else { - if (__Pyx_PyLong_IsNeg(op1)) - return 1; - } - uintval = (unsigned long) intval; -#if PyLong_SHIFT * 4 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 4)) { - unequal = (size != 5) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[4] != ((uintval >> (4 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif -#if PyLong_SHIFT * 3 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 3)) { - unequal = (size != 4) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif -#if PyLong_SHIFT * 2 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 2)) { - unequal = (size != 3) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif -#if PyLong_SHIFT * 1 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 1)) { - unequal = (size != 2) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif - unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK)); - return (unequal != 0); - } - #endif - if (PyFloat_CheckExact(op1)) { - const long b = intval; - double a = __Pyx_PyFloat_AS_DOUBLE(op1); - return ((double)a != (double)b); - } - return __Pyx_PyObject_IsTrueAndDecref( - PyObject_RichCompare(op1, op2, Py_NE)); -} - -/* PyObjectCallNoArg */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallNoArg(PyObject *func) { - PyObject *arg[2] = {NULL, NULL}; - return __Pyx_PyObject_FastCall(func, arg + 1, 0 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); -} - -/* RaiseUnexpectedTypeError */ -static int -__Pyx_RaiseUnexpectedTypeError(const char *expected, PyObject *obj) -{ - __Pyx_TypeName obj_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(obj)); - PyErr_Format(PyExc_TypeError, "Expected %s, got " __Pyx_FMT_TYPENAME, - expected, obj_type_name); - __Pyx_DECREF_TypeName(obj_type_name); - return 0; -} - -/* PyLongCompare */ -static CYTHON_INLINE int __Pyx_PyLong_BoolEqObjC(PyObject *op1, PyObject *op2, long intval, long inplace) { - CYTHON_MAYBE_UNUSED_VAR(intval); - CYTHON_UNUSED_VAR(inplace); - if (op1 == op2) { - return 1; - } - #if CYTHON_USE_PYLONG_INTERNALS - if (likely(PyLong_CheckExact(op1))) { - int unequal; - unsigned long uintval; - Py_ssize_t size = __Pyx_PyLong_DigitCount(op1); - const digit* digits = __Pyx_PyLong_Digits(op1); - if (intval == 0) { - return (__Pyx_PyLong_IsZero(op1) == 1); - } else if (intval < 0) { - if (__Pyx_PyLong_IsNonNeg(op1)) - return 0; - intval = -intval; - } else { - if (__Pyx_PyLong_IsNeg(op1)) - return 0; - } - uintval = (unsigned long) intval; -#if PyLong_SHIFT * 4 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 4)) { - unequal = (size != 5) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[4] != ((uintval >> (4 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif -#if PyLong_SHIFT * 3 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 3)) { - unequal = (size != 4) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[3] != ((uintval >> (3 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif -#if PyLong_SHIFT * 2 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 2)) { - unequal = (size != 3) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)) | (digits[2] != ((uintval >> (2 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif -#if PyLong_SHIFT * 1 < SIZEOF_LONG*8 - if (uintval >> (PyLong_SHIFT * 1)) { - unequal = (size != 2) || (digits[0] != (uintval & (unsigned long) PyLong_MASK)) - | (digits[1] != ((uintval >> (1 * PyLong_SHIFT)) & (unsigned long) PyLong_MASK)); - } else -#endif - unequal = (size != 1) || (((unsigned long) digits[0]) != (uintval & (unsigned long) PyLong_MASK)); - return (unequal == 0); - } - #endif - if (PyFloat_CheckExact(op1)) { - const long b = intval; - double a = __Pyx_PyFloat_AS_DOUBLE(op1); - return ((double)a == (double)b); - } - return __Pyx_PyObject_IsTrueAndDecref( - PyObject_RichCompare(op1, op2, Py_EQ)); -} - -/* GetItemInt */ -static PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) { - PyObject *r; - if (unlikely(!j)) return NULL; - r = PyObject_GetItem(o, j); - Py_DECREF(j); - return r; -} -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_List_Fast(PyObject *o, Py_ssize_t i, - CYTHON_NCP_UNUSED int wraparound, - CYTHON_NCP_UNUSED int boundscheck) { -#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE && !CYTHON_AVOID_BORROWED_REFS && !CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - Py_ssize_t wrapped_i = i; - if (wraparound & unlikely(i < 0)) { - wrapped_i += PyList_GET_SIZE(o); - } - if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyList_GET_SIZE(o)))) { - PyObject *r = PyList_GET_ITEM(o, wrapped_i); - Py_INCREF(r); - return r; - } - return __Pyx_GetItemInt_Generic(o, PyLong_FromSsize_t(i)); -#else - return PySequence_GetItem(o, i); -#endif -} -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Tuple_Fast(PyObject *o, Py_ssize_t i, - CYTHON_NCP_UNUSED int wraparound, - CYTHON_NCP_UNUSED int boundscheck) { -#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE && !CYTHON_AVOID_BORROWED_REFS - Py_ssize_t wrapped_i = i; - if (wraparound & unlikely(i < 0)) { - wrapped_i += PyTuple_GET_SIZE(o); - } - if ((!boundscheck) || likely(__Pyx_is_valid_index(wrapped_i, PyTuple_GET_SIZE(o)))) { - PyObject *r = PyTuple_GET_ITEM(o, wrapped_i); - Py_INCREF(r); - return r; - } - return __Pyx_GetItemInt_Generic(o, PyLong_FromSsize_t(i)); -#else - return PySequence_GetItem(o, i); -#endif -} -static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Fast(PyObject *o, Py_ssize_t i, int is_list, - CYTHON_NCP_UNUSED int wraparound, - CYTHON_NCP_UNUSED int boundscheck) { -#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE && !CYTHON_AVOID_BORROWED_REFS && CYTHON_USE_TYPE_SLOTS - if (is_list || PyList_CheckExact(o)) { - Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyList_GET_SIZE(o); - if ((!boundscheck) || (likely(__Pyx_is_valid_index(n, PyList_GET_SIZE(o))))) { - return __Pyx_PyList_GetItemRef(o, n); - } - } - else if (PyTuple_CheckExact(o)) { - Py_ssize_t n = ((!wraparound) | likely(i >= 0)) ? i : i + PyTuple_GET_SIZE(o); - if ((!boundscheck) || likely(__Pyx_is_valid_index(n, PyTuple_GET_SIZE(o)))) { - PyObject *r = PyTuple_GET_ITEM(o, n); - Py_INCREF(r); - return r; - } - } else { - PyMappingMethods *mm = Py_TYPE(o)->tp_as_mapping; - PySequenceMethods *sm = Py_TYPE(o)->tp_as_sequence; - if (mm && mm->mp_subscript) { - PyObject *r, *key = PyLong_FromSsize_t(i); - if (unlikely(!key)) return NULL; - r = mm->mp_subscript(o, key); - Py_DECREF(key); - return r; - } - if (likely(sm && sm->sq_item)) { - if (wraparound && unlikely(i < 0) && likely(sm->sq_length)) { - Py_ssize_t l = sm->sq_length(o); - if (likely(l >= 0)) { - i += l; - } else { - if (!PyErr_ExceptionMatches(PyExc_OverflowError)) - return NULL; - PyErr_Clear(); - } - } - return sm->sq_item(o, i); - } - } -#else - if (is_list || !PyMapping_Check(o)) { - return PySequence_GetItem(o, i); - } -#endif - return __Pyx_GetItemInt_Generic(o, PyLong_FromSsize_t(i)); -} - -/* PyObjectCallOneArg */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallOneArg(PyObject *func, PyObject *arg) { - PyObject *args[2] = {NULL, arg}; - return __Pyx_PyObject_FastCall(func, args+1, 1 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); -} - -/* ObjectGetItem */ -#if CYTHON_USE_TYPE_SLOTS -static PyObject *__Pyx_PyObject_GetIndex(PyObject *obj, PyObject *index) { - PyObject *runerr = NULL; - Py_ssize_t key_value; - key_value = __Pyx_PyIndex_AsSsize_t(index); - if (likely(key_value != -1 || !(runerr = PyErr_Occurred()))) { - return __Pyx_GetItemInt_Fast(obj, key_value, 0, 1, 1); - } - if (PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { - __Pyx_TypeName index_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(index)); - PyErr_Clear(); - PyErr_Format(PyExc_IndexError, - "cannot fit '" __Pyx_FMT_TYPENAME "' into an index-sized integer", index_type_name); - __Pyx_DECREF_TypeName(index_type_name); - } - return NULL; -} -static PyObject *__Pyx_PyObject_GetItem_Slow(PyObject *obj, PyObject *key) { - __Pyx_TypeName obj_type_name; - if (likely(PyType_Check(obj))) { - PyObject *meth = __Pyx_PyObject_GetAttrStrNoError(obj, __pyx_mstate_global->__pyx_n_u_class_getitem); - if (!meth) { - PyErr_Clear(); - } else { - PyObject *result = __Pyx_PyObject_CallOneArg(meth, key); - Py_DECREF(meth); - return result; - } - } - obj_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(obj)); - PyErr_Format(PyExc_TypeError, - "'" __Pyx_FMT_TYPENAME "' object is not subscriptable", obj_type_name); - __Pyx_DECREF_TypeName(obj_type_name); - return NULL; -} -static PyObject *__Pyx_PyObject_GetItem(PyObject *obj, PyObject *key) { - PyTypeObject *tp = Py_TYPE(obj); - PyMappingMethods *mm = tp->tp_as_mapping; - PySequenceMethods *sm = tp->tp_as_sequence; - if (likely(mm && mm->mp_subscript)) { - return mm->mp_subscript(obj, key); - } - if (likely(sm && sm->sq_item)) { - return __Pyx_PyObject_GetIndex(obj, key); - } - return __Pyx_PyObject_GetItem_Slow(obj, key); -} -#endif - -/* PyLongBinop */ -#if !CYTHON_COMPILING_IN_PYPY -static PyObject* __Pyx_Fallback___Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, int inplace) { - return (inplace ? PyNumber_InPlaceAdd : PyNumber_Add)(op1, op2); -} -#if CYTHON_USE_PYLONG_INTERNALS -static PyObject* __Pyx_Unpacked___Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { - CYTHON_MAYBE_UNUSED_VAR(inplace); - CYTHON_UNUSED_VAR(zerodivision_check); - const long b = intval; - long a, x; -#ifdef HAVE_LONG_LONG - const PY_LONG_LONG llb = intval; - PY_LONG_LONG lla, llx; -#endif - if (unlikely(__Pyx_PyLong_IsZero(op1))) { - return __Pyx_NewRef(op2); - } - if (likely(__Pyx_PyLong_IsCompact(op1))) { - a = __Pyx_PyLong_CompactValue(op1); - } else { - const digit* digits = __Pyx_PyLong_Digits(op1); - const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(op1); - switch (size) { - case -2: - if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { - lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case 2: - if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { - lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case -3: - if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { - lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case 3: - if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { - lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case -4: - if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { - lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case 4: - if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { - lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - default: return PyLong_Type.tp_as_number->nb_add(op1, op2); - } - } - x = a + b; - return PyLong_FromLong(x); -#ifdef HAVE_LONG_LONG - long_long: - llx = lla + llb; - return PyLong_FromLongLong(llx); -#endif - return __Pyx_Fallback___Pyx_PyLong_AddObjC(op1, op2, inplace); - - -} -#endif -static PyObject* __Pyx_Float___Pyx_PyLong_AddObjC(PyObject *float_val, long intval, int zerodivision_check) { - CYTHON_UNUSED_VAR(zerodivision_check); - const long b = intval; - double a = __Pyx_PyFloat_AS_DOUBLE(float_val); - double result; - - result = ((double)a) + (double)b; - return PyFloat_FromDouble(result); -} -static CYTHON_INLINE PyObject* __Pyx_PyLong_AddObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { - CYTHON_MAYBE_UNUSED_VAR(intval); - CYTHON_UNUSED_VAR(zerodivision_check); - #if CYTHON_USE_PYLONG_INTERNALS - if (likely(PyLong_CheckExact(op1))) { - return __Pyx_Unpacked___Pyx_PyLong_AddObjC(op1, op2, intval, inplace, zerodivision_check); - } - #endif - if (PyFloat_CheckExact(op1)) { - return __Pyx_Float___Pyx_PyLong_AddObjC(op1, intval, zerodivision_check); - } - return __Pyx_Fallback___Pyx_PyLong_AddObjC(op1, op2, inplace); -} -#endif - -/* DictGetItem */ -#if !CYTHON_COMPILING_IN_PYPY -static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { - PyObject *value; - if (unlikely(__Pyx_PyDict_GetItemRef(d, key, &value) == 0)) { // no value, no error - if (unlikely(PyTuple_Check(key))) { - PyObject* args = PyTuple_Pack(1, key); - if (likely(args)) { - PyErr_SetObject(PyExc_KeyError, args); - Py_DECREF(args); - } - } else { - PyErr_SetObject(PyExc_KeyError, key); - } - } - return value; -} -#endif - -/* PyLongBinop */ -#if !CYTHON_COMPILING_IN_PYPY -static PyObject* __Pyx_Fallback___Pyx_PyLong_SubtractObjC(PyObject *op1, PyObject *op2, int inplace) { - return (inplace ? PyNumber_InPlaceSubtract : PyNumber_Subtract)(op1, op2); -} -#if CYTHON_USE_PYLONG_INTERNALS -static PyObject* __Pyx_Unpacked___Pyx_PyLong_SubtractObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { - CYTHON_MAYBE_UNUSED_VAR(inplace); - CYTHON_UNUSED_VAR(zerodivision_check); - const long b = intval; - long a, x; -#ifdef HAVE_LONG_LONG - const PY_LONG_LONG llb = intval; - PY_LONG_LONG lla, llx; -#endif - if (unlikely(__Pyx_PyLong_IsZero(op1))) { - return PyLong_FromLong(-intval); - } - if (likely(__Pyx_PyLong_IsCompact(op1))) { - a = __Pyx_PyLong_CompactValue(op1); - } else { - const digit* digits = __Pyx_PyLong_Digits(op1); - const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(op1); - switch (size) { - case -2: - if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - a = -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { - lla = -(PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case 2: - if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { - a = (long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 2 * PyLong_SHIFT) { - lla = (PY_LONG_LONG) (((((unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case -3: - if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - a = -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { - lla = -(PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case 3: - if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { - a = (long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 3 * PyLong_SHIFT) { - lla = (PY_LONG_LONG) (((((((unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case -4: - if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - a = -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { - lla = -(PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - case 4: - if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { - a = (long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - break; - #ifdef HAVE_LONG_LONG - } else if (8 * sizeof(PY_LONG_LONG) - 1 > 4 * PyLong_SHIFT) { - lla = (PY_LONG_LONG) (((((((((unsigned PY_LONG_LONG)digits[3]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[2]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[1]) << PyLong_SHIFT) | (unsigned PY_LONG_LONG)digits[0])); - goto long_long; - #endif - } - CYTHON_FALLTHROUGH; - default: return PyLong_Type.tp_as_number->nb_subtract(op1, op2); - } - } - x = a - b; - return PyLong_FromLong(x); -#ifdef HAVE_LONG_LONG - long_long: - llx = lla - llb; - return PyLong_FromLongLong(llx); -#endif - return __Pyx_Fallback___Pyx_PyLong_SubtractObjC(op1, op2, inplace); - - -} -#endif -static PyObject* __Pyx_Float___Pyx_PyLong_SubtractObjC(PyObject *float_val, long intval, int zerodivision_check) { - CYTHON_UNUSED_VAR(zerodivision_check); - const long b = intval; - double a = __Pyx_PyFloat_AS_DOUBLE(float_val); - double result; - - result = ((double)a) - (double)b; - return PyFloat_FromDouble(result); -} -static CYTHON_INLINE PyObject* __Pyx_PyLong_SubtractObjC(PyObject *op1, PyObject *op2, long intval, int inplace, int zerodivision_check) { - CYTHON_MAYBE_UNUSED_VAR(intval); - CYTHON_UNUSED_VAR(zerodivision_check); - #if CYTHON_USE_PYLONG_INTERNALS - if (likely(PyLong_CheckExact(op1))) { - return __Pyx_Unpacked___Pyx_PyLong_SubtractObjC(op1, op2, intval, inplace, zerodivision_check); - } - #endif - if (PyFloat_CheckExact(op1)) { - return __Pyx_Float___Pyx_PyLong_SubtractObjC(op1, intval, zerodivision_check); - } - return __Pyx_Fallback___Pyx_PyLong_SubtractObjC(op1, op2, inplace); -} -#endif - -/* PyObjectCall2Args */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyObject* arg1, PyObject* arg2) { - PyObject *args[3] = {NULL, arg1, arg2}; - return __Pyx_PyObject_FastCall(function, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET); -} - -/* PyObjectGetMethod */ -static int __Pyx_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) { - PyObject *attr; -#if CYTHON_UNPACK_METHODS && CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_PYTYPE_LOOKUP - __Pyx_TypeName type_name; - PyTypeObject *tp = Py_TYPE(obj); - PyObject *descr; - descrgetfunc f = NULL; - PyObject **dictptr, *dict; - int meth_found = 0; - assert (*method == NULL); - if (unlikely(tp->tp_getattro != PyObject_GenericGetAttr)) { - attr = __Pyx_PyObject_GetAttrStr(obj, name); - goto try_unpack; - } - if (unlikely(tp->tp_dict == NULL) && unlikely(PyType_Ready(tp) < 0)) { - return 0; - } - descr = _PyType_Lookup(tp, name); - if (likely(descr != NULL)) { - Py_INCREF(descr); -#if defined(Py_TPFLAGS_METHOD_DESCRIPTOR) && Py_TPFLAGS_METHOD_DESCRIPTOR - if (__Pyx_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) -#else - #ifdef __Pyx_CyFunction_USED - if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type) || __Pyx_CyFunction_Check(descr))) - #else - if (likely(PyFunction_Check(descr) || __Pyx_IS_TYPE(descr, &PyMethodDescr_Type))) - #endif -#endif - { - meth_found = 1; - } else { - f = Py_TYPE(descr)->tp_descr_get; - if (f != NULL && PyDescr_IsData(descr)) { - attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); - Py_DECREF(descr); - goto try_unpack; - } - } - } - dictptr = _PyObject_GetDictPtr(obj); - if (dictptr != NULL && (dict = *dictptr) != NULL) { - Py_INCREF(dict); - attr = __Pyx_PyDict_GetItemStr(dict, name); - if (attr != NULL) { - Py_INCREF(attr); - Py_DECREF(dict); - Py_XDECREF(descr); - goto try_unpack; - } - Py_DECREF(dict); - } - if (meth_found) { - *method = descr; - return 1; - } - if (f != NULL) { - attr = f(descr, obj, (PyObject *)Py_TYPE(obj)); - Py_DECREF(descr); - goto try_unpack; - } - if (likely(descr != NULL)) { - *method = descr; - return 0; - } - type_name = __Pyx_PyType_GetFullyQualifiedName(tp); - PyErr_Format(PyExc_AttributeError, - "'" __Pyx_FMT_TYPENAME "' object has no attribute '%U'", - type_name, name); - __Pyx_DECREF_TypeName(type_name); - return 0; -#else - attr = __Pyx_PyObject_GetAttrStr(obj, name); - goto try_unpack; -#endif -try_unpack: -#if CYTHON_UNPACK_METHODS - if (likely(attr) && PyMethod_Check(attr) && likely(PyMethod_GET_SELF(attr) == obj)) { - PyObject *function = PyMethod_GET_FUNCTION(attr); - Py_INCREF(function); - Py_DECREF(attr); - *method = function; - return 1; - } -#endif - *method = attr; - return 0; -} - -/* PyObjectCallMethod1 */ -#if !(CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C0000) -static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) { - PyObject *result = __Pyx_PyObject_CallOneArg(method, arg); - Py_DECREF(method); - return result; -} -#endif -static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) { -#if CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C0000 - PyObject *args[2] = {obj, arg}; - (void) __Pyx_PyObject_GetMethod; - (void) __Pyx_PyObject_CallOneArg; - (void) __Pyx_PyObject_Call2Args; - return PyObject_VectorcallMethod(method_name, args, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL); -#else - PyObject *method = NULL, *result; - int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method); - if (likely(is_method)) { - result = __Pyx_PyObject_Call2Args(method, obj, arg); - Py_DECREF(method); - return result; - } - if (unlikely(!method)) return NULL; - return __Pyx__PyObject_CallMethod1(method, arg); -#endif -} - -/* append */ -static CYTHON_INLINE int __Pyx_PyObject_Append(PyObject* L, PyObject* x) { - if (likely(PyList_CheckExact(L))) { - if (unlikely(__Pyx_PyList_Append(L, x) < 0)) return -1; - } else { - PyObject* retval = __Pyx_PyObject_CallMethod1(L, __pyx_mstate_global->__pyx_n_u_append, x); - if (unlikely(!retval)) - return -1; - Py_DECREF(retval); - } - return 0; -} - -/* PyFloatBinop */ -#if !CYTHON_COMPILING_IN_PYPY -static int __Pyx_PyFloat_BoolEqObjC(PyObject *op1, PyObject *op2, double floatval, int inplace, int zerodivision_check) { - const double b = floatval; - double a; - CYTHON_UNUSED_VAR(inplace); - CYTHON_UNUSED_VAR(zerodivision_check); - if (op1 == op2) { - return 1; - } - if (likely(PyFloat_CheckExact(op1))) { - a = __Pyx_PyFloat_AS_DOUBLE(op1); - - } else - if (likely(PyLong_CheckExact(op1))) { - #if CYTHON_USE_PYLONG_INTERNALS - if (__Pyx_PyLong_IsZero(op1)) { - a = 0.0; - - } else if (__Pyx_PyLong_IsCompact(op1)) { - a = (double) __Pyx_PyLong_CompactValue(op1); - } else { - const digit* digits = __Pyx_PyLong_Digits(op1); - const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(op1); - switch (size) { - case -2: - case 2: - if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT && ((8 * sizeof(unsigned long) < 53) || (1 * PyLong_SHIFT < 53))) { - a = (double) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - if ((8 * sizeof(unsigned long) < 53) || (2 * PyLong_SHIFT < 53) || (a < (double) ((PY_LONG_LONG)1 << 53))) { - if (size == -2) - a = -a; - break; - } - } - CYTHON_FALLTHROUGH; - case -3: - case 3: - if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT && ((8 * sizeof(unsigned long) < 53) || (2 * PyLong_SHIFT < 53))) { - a = (double) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - if ((8 * sizeof(unsigned long) < 53) || (3 * PyLong_SHIFT < 53) || (a < (double) ((PY_LONG_LONG)1 << 53))) { - if (size == -3) - a = -a; - break; - } - } - CYTHON_FALLTHROUGH; - case -4: - case 4: - if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT && ((8 * sizeof(unsigned long) < 53) || (3 * PyLong_SHIFT < 53))) { - a = (double) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0])); - if ((8 * sizeof(unsigned long) < 53) || (4 * PyLong_SHIFT < 53) || (a < (double) ((PY_LONG_LONG)1 << 53))) { - if (size == -4) - a = -a; - break; - } - } - CYTHON_FALLTHROUGH; - default: - #endif - { - PyObject *res = - #if CYTHON_USE_TYPE_SLOTS || __PYX_LIMITED_VERSION_HEX >= 0x030A0000 - __Pyx_PyType_GetSlot((&PyFloat_Type), tp_richcompare, richcmpfunc) - #else - PyObject_RichCompare - #endif - (op2, op1, - Py_EQ); - return __Pyx_PyObject_IsTrueAndDecref( - res); - } - #if CYTHON_USE_PYLONG_INTERNALS - } - } - #endif - } else { - return __Pyx_PyObject_IsTrueAndDecref( - PyObject_RichCompare(op1, op2, Py_EQ)); - } - if (a == b) { - return 1; - } else { - return 0; - } -} -#endif - -/* PyObjectLookupSpecial */ -#if CYTHON_USE_PYTYPE_LOOKUP && CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx__PyObject_LookupSpecial(PyObject* obj, PyObject* attr_name, int with_error) { - PyObject *res; - PyTypeObject *tp = Py_TYPE(obj); - res = _PyType_Lookup(tp, attr_name); - if (likely(res)) { - descrgetfunc f = Py_TYPE(res)->tp_descr_get; - if (!f) { - Py_INCREF(res); - } else { - res = f(res, obj, (PyObject *)tp); - } - } else if (with_error) { - PyErr_SetObject(PyExc_AttributeError, attr_name); - } - return res; -} -#endif - -/* GetTopmostException */ -#if CYTHON_USE_EXC_INFO_STACK && CYTHON_FAST_THREAD_STATE -static _PyErr_StackItem * -__Pyx_PyErr_GetTopmostException(PyThreadState *tstate) -{ - _PyErr_StackItem *exc_info = tstate->exc_info; - while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) && - exc_info->previous_item != NULL) - { - exc_info = exc_info->previous_item; - } - return exc_info; -} -#endif - -/* SaveResetException */ -#if CYTHON_FAST_THREAD_STATE -static CYTHON_INLINE void __Pyx__ExceptionSave(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { - #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 - _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); - PyObject *exc_value = exc_info->exc_value; - if (exc_value == NULL || exc_value == Py_None) { - *value = NULL; - *type = NULL; - *tb = NULL; - } else { - *value = exc_value; - Py_INCREF(*value); - *type = (PyObject*) Py_TYPE(exc_value); - Py_INCREF(*type); - *tb = PyException_GetTraceback(exc_value); - } - #elif CYTHON_USE_EXC_INFO_STACK - _PyErr_StackItem *exc_info = __Pyx_PyErr_GetTopmostException(tstate); - *type = exc_info->exc_type; - *value = exc_info->exc_value; - *tb = exc_info->exc_traceback; - Py_XINCREF(*type); - Py_XINCREF(*value); - Py_XINCREF(*tb); - #else - *type = tstate->exc_type; - *value = tstate->exc_value; - *tb = tstate->exc_traceback; - Py_XINCREF(*type); - Py_XINCREF(*value); - Py_XINCREF(*tb); - #endif -} -static CYTHON_INLINE void __Pyx__ExceptionReset(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { - #if CYTHON_USE_EXC_INFO_STACK && PY_VERSION_HEX >= 0x030B00a4 - _PyErr_StackItem *exc_info = tstate->exc_info; - PyObject *tmp_value = exc_info->exc_value; - exc_info->exc_value = value; - Py_XDECREF(tmp_value); - Py_XDECREF(type); - Py_XDECREF(tb); - #else - PyObject *tmp_type, *tmp_value, *tmp_tb; - #if CYTHON_USE_EXC_INFO_STACK - _PyErr_StackItem *exc_info = tstate->exc_info; - tmp_type = exc_info->exc_type; - tmp_value = exc_info->exc_value; - tmp_tb = exc_info->exc_traceback; - exc_info->exc_type = type; - exc_info->exc_value = value; - exc_info->exc_traceback = tb; - #else - tmp_type = tstate->exc_type; - tmp_value = tstate->exc_value; - tmp_tb = tstate->exc_traceback; - tstate->exc_type = type; - tstate->exc_value = value; - tstate->exc_traceback = tb; - #endif - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); - #endif -} -#endif - -/* GetException */ -#if CYTHON_FAST_THREAD_STATE -static int __Pyx__GetException(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) -#else -static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) -#endif -{ - PyObject *local_type = NULL, *local_value, *local_tb = NULL; -#if CYTHON_FAST_THREAD_STATE - PyObject *tmp_type, *tmp_value, *tmp_tb; - #if PY_VERSION_HEX >= 0x030C0000 - local_value = tstate->current_exception; - tstate->current_exception = 0; - #else - local_type = tstate->curexc_type; - local_value = tstate->curexc_value; - local_tb = tstate->curexc_traceback; - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; - #endif -#elif __PYX_LIMITED_VERSION_HEX > 0x030C0000 - local_value = PyErr_GetRaisedException(); -#else - PyErr_Fetch(&local_type, &local_value, &local_tb); -#endif -#if __PYX_LIMITED_VERSION_HEX > 0x030C0000 - if (likely(local_value)) { - local_type = (PyObject*) Py_TYPE(local_value); - Py_INCREF(local_type); - local_tb = PyException_GetTraceback(local_value); - } -#else - PyErr_NormalizeException(&local_type, &local_value, &local_tb); -#if CYTHON_FAST_THREAD_STATE - if (unlikely(tstate->curexc_type)) -#else - if (unlikely(PyErr_Occurred())) -#endif - goto bad; - if (local_tb) { - if (unlikely(PyException_SetTraceback(local_value, local_tb) < 0)) - goto bad; - } -#endif // __PYX_LIMITED_VERSION_HEX > 0x030C0000 - Py_XINCREF(local_tb); - Py_XINCREF(local_type); - Py_XINCREF(local_value); - *type = local_type; - *value = local_value; - *tb = local_tb; -#if CYTHON_FAST_THREAD_STATE - #if CYTHON_USE_EXC_INFO_STACK - { - _PyErr_StackItem *exc_info = tstate->exc_info; - #if PY_VERSION_HEX >= 0x030B00a4 - tmp_value = exc_info->exc_value; - exc_info->exc_value = local_value; - tmp_type = NULL; - tmp_tb = NULL; - Py_XDECREF(local_type); - Py_XDECREF(local_tb); - #else - tmp_type = exc_info->exc_type; - tmp_value = exc_info->exc_value; - tmp_tb = exc_info->exc_traceback; - exc_info->exc_type = local_type; - exc_info->exc_value = local_value; - exc_info->exc_traceback = local_tb; - #endif - } - #else - tmp_type = tstate->exc_type; - tmp_value = tstate->exc_value; - tmp_tb = tstate->exc_traceback; - tstate->exc_type = local_type; - tstate->exc_value = local_value; - tstate->exc_traceback = local_tb; - #endif - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -#elif __PYX_LIMITED_VERSION_HEX >= 0x030b0000 - PyErr_SetHandledException(local_value); - Py_XDECREF(local_value); - Py_XDECREF(local_type); - Py_XDECREF(local_tb); -#else - PyErr_SetExcInfo(local_type, local_value, local_tb); -#endif - return 0; -#if __PYX_LIMITED_VERSION_HEX <= 0x030C0000 -bad: - *type = 0; - *value = 0; - *tb = 0; - Py_XDECREF(local_type); - Py_XDECREF(local_value); - Py_XDECREF(local_tb); - return -1; -#endif -} - -/* Import */ -static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) { - PyObject *module = 0; - PyObject *empty_dict = 0; - PyObject *empty_list = 0; - empty_dict = PyDict_New(); - if (unlikely(!empty_dict)) - goto bad; - if (level == -1) { - if (strchr(__Pyx_MODULE_NAME, '.') != (0)) { - module = PyImport_ImportModuleLevelObject( - name, __pyx_mstate_global->__pyx_d, empty_dict, from_list, 1); - if (unlikely(!module)) { - if (unlikely(!PyErr_ExceptionMatches(PyExc_ImportError))) - goto bad; - PyErr_Clear(); - } - } - level = 0; - } - if (!module) { - module = PyImport_ImportModuleLevelObject( - name, __pyx_mstate_global->__pyx_d, empty_dict, from_list, level); - } -bad: - Py_XDECREF(empty_dict); - Py_XDECREF(empty_list); - return module; -} - -/* ImportDottedModule */ -static PyObject *__Pyx__ImportDottedModule_Error(PyObject *name, PyObject *parts_tuple, Py_ssize_t count) { - PyObject *partial_name = NULL, *slice = NULL, *sep = NULL; - Py_ssize_t size; - if (unlikely(PyErr_Occurred())) { - PyErr_Clear(); - } -#if CYTHON_ASSUME_SAFE_SIZE - size = PyTuple_GET_SIZE(parts_tuple); -#else - size = PyTuple_Size(parts_tuple); - if (size < 0) goto bad; -#endif - if (likely(size == count)) { - partial_name = name; - } else { - slice = PySequence_GetSlice(parts_tuple, 0, count); - if (unlikely(!slice)) - goto bad; - sep = PyUnicode_FromStringAndSize(".", 1); - if (unlikely(!sep)) - goto bad; - partial_name = PyUnicode_Join(sep, slice); - } - PyErr_Format( - PyExc_ModuleNotFoundError, - "No module named '%U'", partial_name); -bad: - Py_XDECREF(sep); - Py_XDECREF(slice); - Py_XDECREF(partial_name); - return NULL; -} -static PyObject *__Pyx__ImportDottedModule_Lookup(PyObject *name) { - PyObject *imported_module; -#if (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) ||\ - CYTHON_COMPILING_IN_GRAAL - PyObject *modules = PyImport_GetModuleDict(); - if (unlikely(!modules)) - return NULL; - imported_module = __Pyx_PyDict_GetItemStr(modules, name); - Py_XINCREF(imported_module); -#else - imported_module = PyImport_GetModule(name); -#endif - return imported_module; -} -static PyObject *__Pyx_ImportDottedModule_WalkParts(PyObject *module, PyObject *name, PyObject *parts_tuple) { - Py_ssize_t i, nparts; -#if CYTHON_ASSUME_SAFE_SIZE - nparts = PyTuple_GET_SIZE(parts_tuple); -#else - nparts = PyTuple_Size(parts_tuple); - if (nparts < 0) return NULL; -#endif - for (i=1; i < nparts && module; i++) { - PyObject *part, *submodule; -#if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - part = PyTuple_GET_ITEM(parts_tuple, i); -#else - part = __Pyx_PySequence_ITEM(parts_tuple, i); - if (!part) return NULL; -#endif - submodule = __Pyx_PyObject_GetAttrStrNoError(module, part); -#if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) - Py_DECREF(part); -#endif - Py_DECREF(module); - module = submodule; - } - if (unlikely(!module)) { - return __Pyx__ImportDottedModule_Error(name, parts_tuple, i); - } - return module; -} -static PyObject *__Pyx__ImportDottedModule(PyObject *name, PyObject *parts_tuple) { - PyObject *imported_module; - PyObject *module = __Pyx_Import(name, NULL, 0); - if (!parts_tuple || unlikely(!module)) - return module; - imported_module = __Pyx__ImportDottedModule_Lookup(name); - if (likely(imported_module)) { - Py_DECREF(module); - return imported_module; - } - PyErr_Clear(); - return __Pyx_ImportDottedModule_WalkParts(module, name, parts_tuple); -} -static PyObject *__Pyx_ImportDottedModule(PyObject *name, PyObject *parts_tuple) { -#if CYTHON_COMPILING_IN_CPYTHON - PyObject *module = __Pyx__ImportDottedModule_Lookup(name); - if (likely(module)) { - PyObject *spec = __Pyx_PyObject_GetAttrStrNoError(module, __pyx_mstate_global->__pyx_n_u_spec); - if (likely(spec)) { - PyObject *unsafe = __Pyx_PyObject_GetAttrStrNoError(spec, __pyx_mstate_global->__pyx_n_u_initializing); - if (likely(!unsafe || !__Pyx_PyObject_IsTrue(unsafe))) { - Py_DECREF(spec); - spec = NULL; - } - Py_XDECREF(unsafe); - } - if (likely(!spec)) { - PyErr_Clear(); - return module; - } - Py_DECREF(spec); - Py_DECREF(module); - } else if (PyErr_Occurred()) { - PyErr_Clear(); - } -#endif - return __Pyx__ImportDottedModule(name, parts_tuple); -} - -/* ListPack */ -static PyObject *__Pyx_PyList_Pack(Py_ssize_t n, ...) { - va_list va; - PyObject *l = PyList_New(n); - va_start(va, n); - if (unlikely(!l)) goto end; - for (Py_ssize_t i=0; i__pyx_kp_u__3); - if (unlikely(!module_dot)) { goto modbad; } - full_name = PyUnicode_Concat(module_dot, name); - if (unlikely(!full_name)) { goto modbad; } - #if (CYTHON_COMPILING_IN_PYPY && PYPY_VERSION_NUM < 0x07030400) ||\ - CYTHON_COMPILING_IN_GRAAL - { - PyObject *modules = PyImport_GetModuleDict(); - if (unlikely(!modules)) - goto modbad; - value = PyObject_GetItem(modules, full_name); - } - #else - value = PyImport_GetModule(full_name); - #endif - modbad: - Py_XDECREF(full_name); - Py_XDECREF(module_dot); - Py_XDECREF(module_name); - } - if (unlikely(!value)) { - PyErr_Format(PyExc_ImportError, "cannot import name %S", name); - } - return value; -} - -/* FixUpExtensionType */ -static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject *type) { -#if PY_VERSION_HEX > 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API - CYTHON_UNUSED_VAR(spec); - CYTHON_UNUSED_VAR(type); -#else - const PyType_Slot *slot = spec->slots; - while (slot && slot->slot && slot->slot != Py_tp_members) - slot++; - if (slot && slot->slot == Py_tp_members) { - int changed = 0; -#if !(PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON) - const -#endif - PyMemberDef *memb = (PyMemberDef*) slot->pfunc; - while (memb && memb->name) { - if (memb->name[0] == '_' && memb->name[1] == '_') { -#if PY_VERSION_HEX < 0x030900b1 - if (strcmp(memb->name, "__weaklistoffset__") == 0) { - assert(memb->type == T_PYSSIZET); - assert(memb->flags == READONLY); - type->tp_weaklistoffset = memb->offset; - changed = 1; - } - else if (strcmp(memb->name, "__dictoffset__") == 0) { - assert(memb->type == T_PYSSIZET); - assert(memb->flags == READONLY); - type->tp_dictoffset = memb->offset; - changed = 1; - } -#if CYTHON_METH_FASTCALL - else if (strcmp(memb->name, "__vectorcalloffset__") == 0) { - assert(memb->type == T_PYSSIZET); - assert(memb->flags == READONLY); -#if PY_VERSION_HEX >= 0x030800b4 - type->tp_vectorcall_offset = memb->offset; -#else - type->tp_print = (printfunc) memb->offset; -#endif - changed = 1; - } -#endif -#else - if ((0)); -#endif -#if PY_VERSION_HEX <= 0x030900b1 && CYTHON_COMPILING_IN_CPYTHON - else if (strcmp(memb->name, "__module__") == 0) { - PyObject *descr; - assert(memb->type == T_OBJECT); - assert(memb->flags == 0 || memb->flags == READONLY); - descr = PyDescr_NewMember(type, memb); - if (unlikely(!descr)) - return -1; - if (unlikely(PyDict_SetItem(type->tp_dict, PyDescr_NAME(descr), descr) < 0)) { - Py_DECREF(descr); - return -1; - } - Py_DECREF(descr); - changed = 1; - } -#endif - } - memb++; - } - if (changed) - PyType_Modified(type); - } -#endif - return 0; -} - -/* FetchSharedCythonModule */ -static PyObject *__Pyx_FetchSharedCythonABIModule(void) { - return __Pyx_PyImport_AddModuleRef(__PYX_ABI_MODULE_NAME); -} - -/* dict_setdefault */ -static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, - int is_safe_type) { - PyObject* value; - CYTHON_MAYBE_UNUSED_VAR(is_safe_type); -#if CYTHON_COMPILING_IN_LIMITED_API - value = PyObject_CallMethod(d, "setdefault", "OO", key, default_value); -#elif PY_VERSION_HEX >= 0x030d0000 - PyDict_SetDefaultRef(d, key, default_value, &value); -#else - value = PyDict_SetDefault(d, key, default_value); - if (unlikely(!value)) return NULL; - Py_INCREF(value); -#endif - return value; -} - -/* FetchCommonType */ -static int __Pyx_VerifyCachedType(PyObject *cached_type, - const char *name, - Py_ssize_t expected_basicsize) { - Py_ssize_t basicsize; - if (!PyType_Check(cached_type)) { - PyErr_Format(PyExc_TypeError, - "Shared Cython type %.200s is not a type object", name); - return -1; - } -#if CYTHON_COMPILING_IN_LIMITED_API - PyObject *py_basicsize; - py_basicsize = PyObject_GetAttrString(cached_type, "__basicsize__"); - if (unlikely(!py_basicsize)) return -1; - basicsize = PyLong_AsSsize_t(py_basicsize); - Py_DECREF(py_basicsize); - py_basicsize = NULL; - if (unlikely(basicsize == (Py_ssize_t)-1) && PyErr_Occurred()) return -1; -#else - basicsize = ((PyTypeObject*) cached_type)->tp_basicsize; -#endif - if (basicsize != expected_basicsize) { - PyErr_Format(PyExc_TypeError, - "Shared Cython type %.200s has the wrong size, try recompiling", - name); - return -1; - } - return 0; -} -static PyTypeObject *__Pyx_FetchCommonTypeFromSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { - PyObject *abi_module = NULL, *cached_type = NULL, *abi_module_dict, *new_cached_type, *py_object_name; - int get_item_ref_result; - const char* object_name = strrchr(spec->name, '.'); - object_name = object_name ? object_name+1 : spec->name; - py_object_name = PyUnicode_FromString(object_name); - if (!py_object_name) return NULL; - abi_module = __Pyx_FetchSharedCythonABIModule(); - if (!abi_module) goto done; - abi_module_dict = PyModule_GetDict(abi_module); - if (!abi_module_dict) goto done; - get_item_ref_result = __Pyx_PyDict_GetItemRef(abi_module_dict, py_object_name, &cached_type); - if (get_item_ref_result == 1) { - if (__Pyx_VerifyCachedType( - cached_type, - object_name, - spec->basicsize) < 0) { - goto bad; - } - goto done; - } else if (unlikely(get_item_ref_result == -1)) { - goto bad; - } - CYTHON_UNUSED_VAR(module); - cached_type = __Pyx_PyType_FromModuleAndSpec(abi_module, spec, bases); - if (unlikely(!cached_type)) goto bad; - if (unlikely(__Pyx_fix_up_extension_type_from_spec(spec, (PyTypeObject *) cached_type) < 0)) goto bad; - new_cached_type = __Pyx_PyDict_SetDefault(abi_module_dict, py_object_name, cached_type, 1); - if (unlikely(new_cached_type != cached_type)) { - if (unlikely(!new_cached_type)) goto bad; - Py_DECREF(cached_type); - cached_type = new_cached_type; - if (__Pyx_VerifyCachedType( - cached_type, - object_name, - spec->basicsize) < 0) { - goto bad; - } - goto done; - } else { - Py_DECREF(new_cached_type); - } -done: - Py_XDECREF(abi_module); - Py_DECREF(py_object_name); - assert(cached_type == NULL || PyType_Check(cached_type)); - return (PyTypeObject *) cached_type; -bad: - Py_XDECREF(cached_type); - cached_type = NULL; - goto done; -} - -/* CallTypeTraverse */ -#if !CYTHON_USE_TYPE_SPECS || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x03090000) -#else -static int __Pyx_call_type_traverse(PyObject *o, int always_call, visitproc visit, void *arg) { - #if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x03090000 - if (__Pyx_get_runtime_version() < 0x03090000) return 0; - #endif - if (!always_call) { - PyTypeObject *base = __Pyx_PyObject_GetSlot(o, tp_base, PyTypeObject*); - unsigned long flags = PyType_GetFlags(base); - if (flags & Py_TPFLAGS_HEAPTYPE) { - return 0; - } - } - Py_VISIT((PyObject*)Py_TYPE(o)); - return 0; -} -#endif - -/* PyMethodNew */ -#if CYTHON_COMPILING_IN_LIMITED_API -static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { - PyObject *result; - CYTHON_UNUSED_VAR(typ); - if (!self) - return __Pyx_NewRef(func); - #if __PYX_LIMITED_VERSION_HEX >= 0x030C0000 - { - PyObject *args[] = {func, self}; - result = PyObject_Vectorcall(__pyx_mstate_global->__Pyx_CachedMethodType, args, 2, NULL); - } - #else - result = PyObject_CallFunctionObjArgs(__pyx_mstate_global->__Pyx_CachedMethodType, func, self, NULL); - #endif - return result; -} -#else -static PyObject *__Pyx_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { - CYTHON_UNUSED_VAR(typ); - if (!self) - return __Pyx_NewRef(func); - return PyMethod_New(func, self); -} -#endif - -/* PyVectorcallFastCallDict */ -#if CYTHON_METH_FASTCALL && (CYTHON_VECTORCALL || CYTHON_BACKPORT_VECTORCALL) -static PyObject *__Pyx_PyVectorcall_FastCallDict_kw(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) -{ - PyObject *res = NULL; - PyObject *kwnames; - PyObject **newargs; - PyObject **kwvalues; - Py_ssize_t i, pos; - size_t j; - PyObject *key, *value; - unsigned long keys_are_strings; - #if !CYTHON_ASSUME_SAFE_SIZE - Py_ssize_t nkw = PyDict_Size(kw); - if (unlikely(nkw == -1)) return NULL; - #else - Py_ssize_t nkw = PyDict_GET_SIZE(kw); - #endif - newargs = (PyObject **)PyMem_Malloc((nargs + (size_t)nkw) * sizeof(args[0])); - if (unlikely(newargs == NULL)) { - PyErr_NoMemory(); - return NULL; - } - for (j = 0; j < nargs; j++) newargs[j] = args[j]; - kwnames = PyTuple_New(nkw); - if (unlikely(kwnames == NULL)) { - PyMem_Free(newargs); - return NULL; - } - kwvalues = newargs + nargs; - pos = i = 0; - keys_are_strings = Py_TPFLAGS_UNICODE_SUBCLASS; - while (PyDict_Next(kw, &pos, &key, &value)) { - keys_are_strings &= - #if CYTHON_COMPILING_IN_LIMITED_API - PyType_GetFlags(Py_TYPE(key)); - #else - Py_TYPE(key)->tp_flags; - #endif - Py_INCREF(key); - Py_INCREF(value); - #if !CYTHON_ASSUME_SAFE_MACROS - if (unlikely(PyTuple_SetItem(kwnames, i, key) < 0)) goto cleanup; - #else - PyTuple_SET_ITEM(kwnames, i, key); - #endif - kwvalues[i] = value; - i++; - } - if (unlikely(!keys_are_strings)) { - PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - goto cleanup; - } - res = vc(func, newargs, nargs, kwnames); -cleanup: - Py_DECREF(kwnames); - for (i = 0; i < nkw; i++) - Py_DECREF(kwvalues[i]); - PyMem_Free(newargs); - return res; -} -static CYTHON_INLINE PyObject *__Pyx_PyVectorcall_FastCallDict(PyObject *func, __pyx_vectorcallfunc vc, PyObject *const *args, size_t nargs, PyObject *kw) -{ - Py_ssize_t kw_size = - likely(kw == NULL) ? - 0 : -#if !CYTHON_ASSUME_SAFE_SIZE - PyDict_Size(kw); -#else - PyDict_GET_SIZE(kw); -#endif - if (kw_size == 0) { - return vc(func, args, nargs, NULL); - } -#if !CYTHON_ASSUME_SAFE_SIZE - else if (unlikely(kw_size == -1)) { - return NULL; - } -#endif - return __Pyx_PyVectorcall_FastCallDict_kw(func, vc, args, nargs, kw); -} -#endif - -/* CythonFunctionShared */ -#if CYTHON_COMPILING_IN_LIMITED_API -static CYTHON_INLINE int __Pyx__IsSameCyOrCFunctionNoMethod(PyObject *func, void (*cfunc)(void)) { - if (__Pyx_CyFunction_Check(func)) { - return PyCFunction_GetFunction(((__pyx_CyFunctionObject*)func)->func) == (PyCFunction) cfunc; - } else if (PyCFunction_Check(func)) { - return PyCFunction_GetFunction(func) == (PyCFunction) cfunc; - } - return 0; -} -static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void (*cfunc)(void)) { - if ((PyObject*)Py_TYPE(func) == __pyx_mstate_global->__Pyx_CachedMethodType) { - int result; - PyObject *newFunc = PyObject_GetAttr(func, __pyx_mstate_global->__pyx_n_u_func); - if (unlikely(!newFunc)) { - PyErr_Clear(); // It's only an optimization, so don't throw an error - return 0; - } - result = __Pyx__IsSameCyOrCFunctionNoMethod(newFunc, cfunc); - Py_DECREF(newFunc); - return result; - } - return __Pyx__IsSameCyOrCFunctionNoMethod(func, cfunc); -} -#else -static CYTHON_INLINE int __Pyx__IsSameCyOrCFunction(PyObject *func, void (*cfunc)(void)) { - if (PyMethod_Check(func)) { - func = PyMethod_GET_FUNCTION(func); - } - return __Pyx_CyOrPyCFunction_Check(func) && __Pyx_CyOrPyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; -} -#endif -static CYTHON_INLINE void __Pyx__CyFunction_SetClassObj(__pyx_CyFunctionObject* f, PyObject* classobj) { -#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API - __Pyx_Py_XDECREF_SET( - __Pyx_CyFunction_GetClassObj(f), - ((classobj) ? __Pyx_NewRef(classobj) : NULL)); -#else - __Pyx_Py_XDECREF_SET( - ((PyCMethodObject *) (f))->mm_class, - (PyTypeObject*)((classobj) ? __Pyx_NewRef(classobj) : NULL)); -#endif -} -static PyObject * -__Pyx_CyFunction_get_doc_locked(__pyx_CyFunctionObject *op) -{ - if (unlikely(op->func_doc == NULL)) { -#if CYTHON_COMPILING_IN_LIMITED_API - op->func_doc = PyObject_GetAttrString(op->func, "__doc__"); - if (unlikely(!op->func_doc)) return NULL; -#else - if (((PyCFunctionObject*)op)->m_ml->ml_doc) { - op->func_doc = PyUnicode_FromString(((PyCFunctionObject*)op)->m_ml->ml_doc); - if (unlikely(op->func_doc == NULL)) - return NULL; - } else { - Py_INCREF(Py_None); - return Py_None; - } -#endif - } - Py_INCREF(op->func_doc); - return op->func_doc; -} -static PyObject * -__Pyx_CyFunction_get_doc(__pyx_CyFunctionObject *op, void *closure) { - PyObject *result; - CYTHON_UNUSED_VAR(closure); - __Pyx_BEGIN_CRITICAL_SECTION(op); - result = __Pyx_CyFunction_get_doc_locked(op); - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static int -__Pyx_CyFunction_set_doc(__pyx_CyFunctionObject *op, PyObject *value, void *context) -{ - CYTHON_UNUSED_VAR(context); - if (value == NULL) { - value = Py_None; - } - Py_INCREF(value); - __Pyx_BEGIN_CRITICAL_SECTION(op); - __Pyx_Py_XDECREF_SET(op->func_doc, value); - __Pyx_END_CRITICAL_SECTION(); - return 0; -} -static PyObject * -__Pyx_CyFunction_get_name_locked(__pyx_CyFunctionObject *op) -{ - if (unlikely(op->func_name == NULL)) { -#if CYTHON_COMPILING_IN_LIMITED_API - op->func_name = PyObject_GetAttrString(op->func, "__name__"); -#else - op->func_name = PyUnicode_InternFromString(((PyCFunctionObject*)op)->m_ml->ml_name); -#endif - if (unlikely(op->func_name == NULL)) - return NULL; - } - Py_INCREF(op->func_name); - return op->func_name; -} -static PyObject * -__Pyx_CyFunction_get_name(__pyx_CyFunctionObject *op, void *context) -{ - PyObject *result = NULL; - CYTHON_UNUSED_VAR(context); - __Pyx_BEGIN_CRITICAL_SECTION(op); - result = __Pyx_CyFunction_get_name_locked(op); - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static int -__Pyx_CyFunction_set_name(__pyx_CyFunctionObject *op, PyObject *value, void *context) -{ - CYTHON_UNUSED_VAR(context); - if (unlikely(value == NULL || !PyUnicode_Check(value))) { - PyErr_SetString(PyExc_TypeError, - "__name__ must be set to a string object"); - return -1; - } - Py_INCREF(value); - __Pyx_BEGIN_CRITICAL_SECTION(op); - __Pyx_Py_XDECREF_SET(op->func_name, value); - __Pyx_END_CRITICAL_SECTION(); - return 0; -} -static PyObject * -__Pyx_CyFunction_get_qualname(__pyx_CyFunctionObject *op, void *context) -{ - CYTHON_UNUSED_VAR(context); - PyObject *result; - __Pyx_BEGIN_CRITICAL_SECTION(op); - Py_INCREF(op->func_qualname); - result = op->func_qualname; - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static int -__Pyx_CyFunction_set_qualname(__pyx_CyFunctionObject *op, PyObject *value, void *context) -{ - CYTHON_UNUSED_VAR(context); - if (unlikely(value == NULL || !PyUnicode_Check(value))) { - PyErr_SetString(PyExc_TypeError, - "__qualname__ must be set to a string object"); - return -1; - } - Py_INCREF(value); - __Pyx_BEGIN_CRITICAL_SECTION(op); - __Pyx_Py_XDECREF_SET(op->func_qualname, value); - __Pyx_END_CRITICAL_SECTION(); - return 0; -} -static PyObject * -__Pyx_CyFunction_get_dict_locked(__pyx_CyFunctionObject *op) -{ - if (unlikely(op->func_dict == NULL)) { - op->func_dict = PyDict_New(); - if (unlikely(op->func_dict == NULL)) - return NULL; - } - Py_INCREF(op->func_dict); - return op->func_dict; -} -static PyObject * -__Pyx_CyFunction_get_dict(__pyx_CyFunctionObject *op, void *context) -{ - CYTHON_UNUSED_VAR(context); - PyObject *result; - __Pyx_BEGIN_CRITICAL_SECTION(op); - result = __Pyx_CyFunction_get_dict_locked(op); - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static int -__Pyx_CyFunction_set_dict(__pyx_CyFunctionObject *op, PyObject *value, void *context) -{ - CYTHON_UNUSED_VAR(context); - if (unlikely(value == NULL)) { - PyErr_SetString(PyExc_TypeError, - "function's dictionary may not be deleted"); - return -1; - } - if (unlikely(!PyDict_Check(value))) { - PyErr_SetString(PyExc_TypeError, - "setting function's dictionary to a non-dict"); - return -1; - } - Py_INCREF(value); - __Pyx_BEGIN_CRITICAL_SECTION(op); - __Pyx_Py_XDECREF_SET(op->func_dict, value); - __Pyx_END_CRITICAL_SECTION(); - return 0; -} -static PyObject * -__Pyx_CyFunction_get_globals(__pyx_CyFunctionObject *op, void *context) -{ - CYTHON_UNUSED_VAR(context); - Py_INCREF(op->func_globals); - return op->func_globals; -} -static PyObject * -__Pyx_CyFunction_get_closure(__pyx_CyFunctionObject *op, void *context) -{ - CYTHON_UNUSED_VAR(op); - CYTHON_UNUSED_VAR(context); - Py_INCREF(Py_None); - return Py_None; -} -static PyObject * -__Pyx_CyFunction_get_code(__pyx_CyFunctionObject *op, void *context) -{ - PyObject* result = (op->func_code) ? op->func_code : Py_None; - CYTHON_UNUSED_VAR(context); - Py_INCREF(result); - return result; -} -static int -__Pyx_CyFunction_init_defaults(__pyx_CyFunctionObject *op) { - int result = 0; - PyObject *res = op->defaults_getter((PyObject *) op); - if (unlikely(!res)) - return -1; - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - op->defaults_tuple = PyTuple_GET_ITEM(res, 0); - Py_INCREF(op->defaults_tuple); - op->defaults_kwdict = PyTuple_GET_ITEM(res, 1); - Py_INCREF(op->defaults_kwdict); - #else - op->defaults_tuple = __Pyx_PySequence_ITEM(res, 0); - if (unlikely(!op->defaults_tuple)) result = -1; - else { - op->defaults_kwdict = __Pyx_PySequence_ITEM(res, 1); - if (unlikely(!op->defaults_kwdict)) result = -1; - } - #endif - Py_DECREF(res); - return result; -} -static int -__Pyx_CyFunction_set_defaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { - CYTHON_UNUSED_VAR(context); - if (!value) { - value = Py_None; - } else if (unlikely(value != Py_None && !PyTuple_Check(value))) { - PyErr_SetString(PyExc_TypeError, - "__defaults__ must be set to a tuple object"); - return -1; - } - PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__defaults__ will not " - "currently affect the values used in function calls", 1); - Py_INCREF(value); - __Pyx_BEGIN_CRITICAL_SECTION(op); - __Pyx_Py_XDECREF_SET(op->defaults_tuple, value); - __Pyx_END_CRITICAL_SECTION(); - return 0; -} -static PyObject * -__Pyx_CyFunction_get_defaults_locked(__pyx_CyFunctionObject *op) { - PyObject* result = op->defaults_tuple; - if (unlikely(!result)) { - if (op->defaults_getter) { - if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; - result = op->defaults_tuple; - } else { - result = Py_None; - } - } - Py_INCREF(result); - return result; -} -static PyObject * -__Pyx_CyFunction_get_defaults(__pyx_CyFunctionObject *op, void *context) { - PyObject* result = NULL; - CYTHON_UNUSED_VAR(context); - __Pyx_BEGIN_CRITICAL_SECTION(op); - result = __Pyx_CyFunction_get_defaults_locked(op); - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static int -__Pyx_CyFunction_set_kwdefaults(__pyx_CyFunctionObject *op, PyObject* value, void *context) { - CYTHON_UNUSED_VAR(context); - if (!value) { - value = Py_None; - } else if (unlikely(value != Py_None && !PyDict_Check(value))) { - PyErr_SetString(PyExc_TypeError, - "__kwdefaults__ must be set to a dict object"); - return -1; - } - PyErr_WarnEx(PyExc_RuntimeWarning, "changes to cyfunction.__kwdefaults__ will not " - "currently affect the values used in function calls", 1); - Py_INCREF(value); - __Pyx_BEGIN_CRITICAL_SECTION(op); - __Pyx_Py_XDECREF_SET(op->defaults_kwdict, value); - __Pyx_END_CRITICAL_SECTION(); - return 0; -} -static PyObject * -__Pyx_CyFunction_get_kwdefaults_locked(__pyx_CyFunctionObject *op) { - PyObject* result = op->defaults_kwdict; - if (unlikely(!result)) { - if (op->defaults_getter) { - if (unlikely(__Pyx_CyFunction_init_defaults(op) < 0)) return NULL; - result = op->defaults_kwdict; - } else { - result = Py_None; - } - } - Py_INCREF(result); - return result; -} -static PyObject * -__Pyx_CyFunction_get_kwdefaults(__pyx_CyFunctionObject *op, void *context) { - PyObject* result; - CYTHON_UNUSED_VAR(context); - __Pyx_BEGIN_CRITICAL_SECTION(op); - result = __Pyx_CyFunction_get_kwdefaults_locked(op); - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static int -__Pyx_CyFunction_set_annotations(__pyx_CyFunctionObject *op, PyObject* value, void *context) { - CYTHON_UNUSED_VAR(context); - if (!value || value == Py_None) { - value = NULL; - } else if (unlikely(!PyDict_Check(value))) { - PyErr_SetString(PyExc_TypeError, - "__annotations__ must be set to a dict object"); - return -1; - } - Py_XINCREF(value); - __Pyx_BEGIN_CRITICAL_SECTION(op); - __Pyx_Py_XDECREF_SET(op->func_annotations, value); - __Pyx_END_CRITICAL_SECTION(); - return 0; -} -static PyObject * -__Pyx_CyFunction_get_annotations_locked(__pyx_CyFunctionObject *op) { - PyObject* result = op->func_annotations; - if (unlikely(!result)) { - result = PyDict_New(); - if (unlikely(!result)) return NULL; - op->func_annotations = result; - } - Py_INCREF(result); - return result; -} -static PyObject * -__Pyx_CyFunction_get_annotations(__pyx_CyFunctionObject *op, void *context) { - PyObject *result; - CYTHON_UNUSED_VAR(context); - __Pyx_BEGIN_CRITICAL_SECTION(op); - result = __Pyx_CyFunction_get_annotations_locked(op); - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static PyObject * -__Pyx_CyFunction_get_is_coroutine_value(__pyx_CyFunctionObject *op) { - int is_coroutine = op->flags & __Pyx_CYFUNCTION_COROUTINE; - if (is_coroutine) { - PyObject *is_coroutine_value, *module, *fromlist, *marker = __pyx_mstate_global->__pyx_n_u_is_coroutine; - fromlist = PyList_New(1); - if (unlikely(!fromlist)) return NULL; - Py_INCREF(marker); -#if CYTHON_ASSUME_SAFE_MACROS - PyList_SET_ITEM(fromlist, 0, marker); -#else - if (unlikely(PyList_SetItem(fromlist, 0, marker) < 0)) { - Py_DECREF(marker); - Py_DECREF(fromlist); - return NULL; - } -#endif - module = PyImport_ImportModuleLevelObject(__pyx_mstate_global->__pyx_n_u_asyncio_coroutines, NULL, NULL, fromlist, 0); - Py_DECREF(fromlist); - if (unlikely(!module)) goto ignore; - is_coroutine_value = __Pyx_PyObject_GetAttrStr(module, marker); - Py_DECREF(module); - if (likely(is_coroutine_value)) { - return is_coroutine_value; - } -ignore: - PyErr_Clear(); - } - return __Pyx_PyBool_FromLong(is_coroutine); -} -static PyObject * -__Pyx_CyFunction_get_is_coroutine(__pyx_CyFunctionObject *op, void *context) { - PyObject *result; - CYTHON_UNUSED_VAR(context); - if (op->func_is_coroutine) { - return __Pyx_NewRef(op->func_is_coroutine); - } - result = __Pyx_CyFunction_get_is_coroutine_value(op); - if (unlikely(!result)) - return NULL; - __Pyx_BEGIN_CRITICAL_SECTION(op); - if (op->func_is_coroutine) { - Py_DECREF(result); - result = __Pyx_NewRef(op->func_is_coroutine); - } else { - op->func_is_coroutine = __Pyx_NewRef(result); - } - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static void __Pyx_CyFunction_raise_argument_count_error(__pyx_CyFunctionObject *func, const char* message, Py_ssize_t size) { -#if CYTHON_COMPILING_IN_LIMITED_API - PyObject *py_name = __Pyx_CyFunction_get_name(func, NULL); - if (!py_name) return; - PyErr_Format(PyExc_TypeError, - "%.200S() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", - py_name, message, size); - Py_DECREF(py_name); -#else - const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; - PyErr_Format(PyExc_TypeError, - "%.200s() %s (%" CYTHON_FORMAT_SSIZE_T "d given)", - name, message, size); -#endif -} -static void __Pyx_CyFunction_raise_type_error(__pyx_CyFunctionObject *func, const char* message) { -#if CYTHON_COMPILING_IN_LIMITED_API - PyObject *py_name = __Pyx_CyFunction_get_name(func, NULL); - if (!py_name) return; - PyErr_Format(PyExc_TypeError, - "%.200S() %s", - py_name, message); - Py_DECREF(py_name); -#else - const char* name = ((PyCFunctionObject*)func)->m_ml->ml_name; - PyErr_Format(PyExc_TypeError, - "%.200s() %s", - name, message); -#endif -} -#if CYTHON_COMPILING_IN_LIMITED_API -static PyObject * -__Pyx_CyFunction_get_module(__pyx_CyFunctionObject *op, void *context) { - CYTHON_UNUSED_VAR(context); - return PyObject_GetAttrString(op->func, "__module__"); -} -static int -__Pyx_CyFunction_set_module(__pyx_CyFunctionObject *op, PyObject* value, void *context) { - CYTHON_UNUSED_VAR(context); - return PyObject_SetAttrString(op->func, "__module__", value); -} -#endif -static PyGetSetDef __pyx_CyFunction_getsets[] = { - {"func_doc", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, - {"__doc__", (getter)__Pyx_CyFunction_get_doc, (setter)__Pyx_CyFunction_set_doc, 0, 0}, - {"func_name", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, - {"__name__", (getter)__Pyx_CyFunction_get_name, (setter)__Pyx_CyFunction_set_name, 0, 0}, - {"__qualname__", (getter)__Pyx_CyFunction_get_qualname, (setter)__Pyx_CyFunction_set_qualname, 0, 0}, - {"func_dict", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, - {"__dict__", (getter)__Pyx_CyFunction_get_dict, (setter)__Pyx_CyFunction_set_dict, 0, 0}, - {"func_globals", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, - {"__globals__", (getter)__Pyx_CyFunction_get_globals, 0, 0, 0}, - {"func_closure", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, - {"__closure__", (getter)__Pyx_CyFunction_get_closure, 0, 0, 0}, - {"func_code", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, - {"__code__", (getter)__Pyx_CyFunction_get_code, 0, 0, 0}, - {"func_defaults", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, - {"__defaults__", (getter)__Pyx_CyFunction_get_defaults, (setter)__Pyx_CyFunction_set_defaults, 0, 0}, - {"__kwdefaults__", (getter)__Pyx_CyFunction_get_kwdefaults, (setter)__Pyx_CyFunction_set_kwdefaults, 0, 0}, - {"__annotations__", (getter)__Pyx_CyFunction_get_annotations, (setter)__Pyx_CyFunction_set_annotations, 0, 0}, - {"_is_coroutine", (getter)__Pyx_CyFunction_get_is_coroutine, 0, 0, 0}, -#if CYTHON_COMPILING_IN_LIMITED_API - {"__module__", (getter)__Pyx_CyFunction_get_module, (setter)__Pyx_CyFunction_set_module, 0, 0}, -#endif - {0, 0, 0, 0, 0} -}; -static PyMemberDef __pyx_CyFunction_members[] = { -#if !CYTHON_COMPILING_IN_LIMITED_API - {"__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, -#endif - {"__dictoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_dict), READONLY, 0}, -#if CYTHON_METH_FASTCALL -#if CYTHON_BACKPORT_VECTORCALL || CYTHON_COMPILING_IN_LIMITED_API - {"__vectorcalloffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_vectorcall), READONLY, 0}, -#else - {"__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - {"__weaklistoffset__", T_PYSSIZET, offsetof(__pyx_CyFunctionObject, func_weakreflist), READONLY, 0}, -#else - {"__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, -#endif -#endif - {0, 0, 0, 0, 0} -}; -static PyObject * -__Pyx_CyFunction_reduce(__pyx_CyFunctionObject *m, PyObject *args) -{ - PyObject *result = NULL; - CYTHON_UNUSED_VAR(args); - __Pyx_BEGIN_CRITICAL_SECTION(m); - Py_INCREF(m->func_qualname); - result = m->func_qualname; - __Pyx_END_CRITICAL_SECTION(); - return result; -} -static PyMethodDef __pyx_CyFunction_methods[] = { - {"__reduce__", (PyCFunction)__Pyx_CyFunction_reduce, METH_VARARGS, 0}, - {0, 0, 0, 0} -}; -#if CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_CyFunction_weakreflist(cyfunc) ((cyfunc)->func_weakreflist) -#else -#define __Pyx_CyFunction_weakreflist(cyfunc) (((PyCFunctionObject*)cyfunc)->m_weakreflist) -#endif -static PyObject *__Pyx_CyFunction_Init(__pyx_CyFunctionObject *op, PyMethodDef *ml, int flags, PyObject* qualname, - PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { -#if !CYTHON_COMPILING_IN_LIMITED_API - PyCFunctionObject *cf = (PyCFunctionObject*) op; -#endif - if (unlikely(op == NULL)) - return NULL; -#if CYTHON_COMPILING_IN_LIMITED_API - op->func = PyCFunction_NewEx(ml, (PyObject*)op, module); - if (unlikely(!op->func)) return NULL; -#endif - op->flags = flags; - __Pyx_CyFunction_weakreflist(op) = NULL; -#if !CYTHON_COMPILING_IN_LIMITED_API - cf->m_ml = ml; - cf->m_self = (PyObject *) op; -#endif - Py_XINCREF(closure); - op->func_closure = closure; -#if !CYTHON_COMPILING_IN_LIMITED_API - Py_XINCREF(module); - cf->m_module = module; -#endif - op->func_dict = NULL; - op->func_name = NULL; - Py_INCREF(qualname); - op->func_qualname = qualname; - op->func_doc = NULL; -#if PY_VERSION_HEX < 0x030900B1 || CYTHON_COMPILING_IN_LIMITED_API - op->func_classobj = NULL; -#else - ((PyCMethodObject*)op)->mm_class = NULL; -#endif - op->func_globals = globals; - Py_INCREF(op->func_globals); - Py_XINCREF(code); - op->func_code = code; - op->defaults = NULL; - op->defaults_tuple = NULL; - op->defaults_kwdict = NULL; - op->defaults_getter = NULL; - op->func_annotations = NULL; - op->func_is_coroutine = NULL; -#if CYTHON_METH_FASTCALL - switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { - case METH_NOARGS: - __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_NOARGS; - break; - case METH_O: - __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_O; - break; - case METH_METHOD | METH_FASTCALL | METH_KEYWORDS: - __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD; - break; - case METH_FASTCALL | METH_KEYWORDS: - __Pyx_CyFunction_func_vectorcall(op) = __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS; - break; - case METH_VARARGS | METH_KEYWORDS: - __Pyx_CyFunction_func_vectorcall(op) = NULL; - break; - default: - PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); - Py_DECREF(op); - return NULL; - } -#endif - return (PyObject *) op; -} -static int -__Pyx_CyFunction_clear(__pyx_CyFunctionObject *m) -{ - Py_CLEAR(m->func_closure); -#if CYTHON_COMPILING_IN_LIMITED_API - Py_CLEAR(m->func); -#else - Py_CLEAR(((PyCFunctionObject*)m)->m_module); -#endif - Py_CLEAR(m->func_dict); - Py_CLEAR(m->func_name); - Py_CLEAR(m->func_qualname); - Py_CLEAR(m->func_doc); - Py_CLEAR(m->func_globals); - Py_CLEAR(m->func_code); -#if !CYTHON_COMPILING_IN_LIMITED_API -#if PY_VERSION_HEX < 0x030900B1 - Py_CLEAR(__Pyx_CyFunction_GetClassObj(m)); -#else - { - PyObject *cls = (PyObject*) ((PyCMethodObject *) (m))->mm_class; - ((PyCMethodObject *) (m))->mm_class = NULL; - Py_XDECREF(cls); - } -#endif -#endif - Py_CLEAR(m->defaults_tuple); - Py_CLEAR(m->defaults_kwdict); - Py_CLEAR(m->func_annotations); - Py_CLEAR(m->func_is_coroutine); - Py_CLEAR(m->defaults); - return 0; -} -static void __Pyx__CyFunction_dealloc(__pyx_CyFunctionObject *m) -{ - if (__Pyx_CyFunction_weakreflist(m) != NULL) - PyObject_ClearWeakRefs((PyObject *) m); - __Pyx_CyFunction_clear(m); - __Pyx_PyHeapTypeObject_GC_Del(m); -} -static void __Pyx_CyFunction_dealloc(__pyx_CyFunctionObject *m) -{ - PyObject_GC_UnTrack(m); - __Pyx__CyFunction_dealloc(m); -} -static int __Pyx_CyFunction_traverse(__pyx_CyFunctionObject *m, visitproc visit, void *arg) -{ - { - int e = __Pyx_call_type_traverse((PyObject*)m, 1, visit, arg); - if (e) return e; - } - Py_VISIT(m->func_closure); -#if CYTHON_COMPILING_IN_LIMITED_API - Py_VISIT(m->func); -#else - Py_VISIT(((PyCFunctionObject*)m)->m_module); -#endif - Py_VISIT(m->func_dict); - __Pyx_VISIT_CONST(m->func_name); - __Pyx_VISIT_CONST(m->func_qualname); - Py_VISIT(m->func_doc); - Py_VISIT(m->func_globals); - __Pyx_VISIT_CONST(m->func_code); -#if !CYTHON_COMPILING_IN_LIMITED_API - Py_VISIT(__Pyx_CyFunction_GetClassObj(m)); -#endif - Py_VISIT(m->defaults_tuple); - Py_VISIT(m->defaults_kwdict); - Py_VISIT(m->func_is_coroutine); - Py_VISIT(m->defaults); - return 0; -} -static PyObject* -__Pyx_CyFunction_repr(__pyx_CyFunctionObject *op) -{ - PyObject *repr; - __Pyx_BEGIN_CRITICAL_SECTION(op); - repr = PyUnicode_FromFormat("", - op->func_qualname, (void *)op); - __Pyx_END_CRITICAL_SECTION(); - return repr; -} -static PyObject * __Pyx_CyFunction_CallMethod(PyObject *func, PyObject *self, PyObject *arg, PyObject *kw) { -#if CYTHON_COMPILING_IN_LIMITED_API - PyObject *f = ((__pyx_CyFunctionObject*)func)->func; - PyCFunction meth; - int flags; - meth = PyCFunction_GetFunction(f); - if (unlikely(!meth)) return NULL; - flags = PyCFunction_GetFlags(f); - if (unlikely(flags < 0)) return NULL; -#else - PyCFunctionObject* f = (PyCFunctionObject*)func; - PyCFunction meth = f->m_ml->ml_meth; - int flags = f->m_ml->ml_flags; -#endif - Py_ssize_t size; - switch (flags & (METH_VARARGS | METH_KEYWORDS | METH_NOARGS | METH_O)) { - case METH_VARARGS: - if (likely(kw == NULL || PyDict_Size(kw) == 0)) - return (*meth)(self, arg); - break; - case METH_VARARGS | METH_KEYWORDS: - return (*(PyCFunctionWithKeywords)(void(*)(void))meth)(self, arg, kw); - case METH_NOARGS: - if (likely(kw == NULL || PyDict_Size(kw) == 0)) { -#if CYTHON_ASSUME_SAFE_SIZE - size = PyTuple_GET_SIZE(arg); -#else - size = PyTuple_Size(arg); - if (unlikely(size < 0)) return NULL; -#endif - if (likely(size == 0)) - return (*meth)(self, NULL); - __Pyx_CyFunction_raise_argument_count_error( - (__pyx_CyFunctionObject*)func, - "takes no arguments", size); - return NULL; - } - break; - case METH_O: - if (likely(kw == NULL || PyDict_Size(kw) == 0)) { -#if CYTHON_ASSUME_SAFE_SIZE - size = PyTuple_GET_SIZE(arg); -#else - size = PyTuple_Size(arg); - if (unlikely(size < 0)) return NULL; -#endif - if (likely(size == 1)) { - PyObject *result, *arg0; - #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS - arg0 = PyTuple_GET_ITEM(arg, 0); - #else - arg0 = __Pyx_PySequence_ITEM(arg, 0); if (unlikely(!arg0)) return NULL; - #endif - result = (*meth)(self, arg0); - #if !(CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS) - Py_DECREF(arg0); - #endif - return result; - } - __Pyx_CyFunction_raise_argument_count_error( - (__pyx_CyFunctionObject*)func, - "takes exactly one argument", size); - return NULL; - } - break; - default: - PyErr_SetString(PyExc_SystemError, "Bad call flags for CyFunction"); - return NULL; - } - __Pyx_CyFunction_raise_type_error( - (__pyx_CyFunctionObject*)func, "takes no keyword arguments"); - return NULL; -} -static CYTHON_INLINE PyObject *__Pyx_CyFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *self, *result; -#if CYTHON_COMPILING_IN_LIMITED_API - self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)func)->func); - if (unlikely(!self) && PyErr_Occurred()) return NULL; -#else - self = ((PyCFunctionObject*)func)->m_self; -#endif - result = __Pyx_CyFunction_CallMethod(func, self, arg, kw); - return result; -} -static PyObject *__Pyx_CyFunction_CallAsMethod(PyObject *func, PyObject *args, PyObject *kw) { - PyObject *result; - __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *) func; -#if CYTHON_METH_FASTCALL && (CYTHON_VECTORCALL || CYTHON_BACKPORT_VECTORCALL) - __pyx_vectorcallfunc vc = __Pyx_CyFunction_func_vectorcall(cyfunc); - if (vc) { -#if CYTHON_ASSUME_SAFE_MACROS && CYTHON_ASSUME_SAFE_SIZE - return __Pyx_PyVectorcall_FastCallDict(func, vc, &PyTuple_GET_ITEM(args, 0), (size_t)PyTuple_GET_SIZE(args), kw); -#else - (void) &__Pyx_PyVectorcall_FastCallDict; - return PyVectorcall_Call(func, args, kw); -#endif - } -#endif - if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { - Py_ssize_t argc; - PyObject *new_args; - PyObject *self; -#if CYTHON_ASSUME_SAFE_SIZE - argc = PyTuple_GET_SIZE(args); -#else - argc = PyTuple_Size(args); - if (unlikely(argc < 0)) return NULL; -#endif - new_args = PyTuple_GetSlice(args, 1, argc); - if (unlikely(!new_args)) - return NULL; - self = PyTuple_GetItem(args, 0); - if (unlikely(!self)) { - Py_DECREF(new_args); - PyErr_Format(PyExc_TypeError, - "unbound method %.200S() needs an argument", - cyfunc->func_qualname); - return NULL; - } - result = __Pyx_CyFunction_CallMethod(func, self, new_args, kw); - Py_DECREF(new_args); - } else { - result = __Pyx_CyFunction_Call(func, args, kw); - } - return result; -} -#if CYTHON_METH_FASTCALL && (CYTHON_VECTORCALL || CYTHON_BACKPORT_VECTORCALL) -static CYTHON_INLINE int __Pyx_CyFunction_Vectorcall_CheckArgs(__pyx_CyFunctionObject *cyfunc, Py_ssize_t nargs, PyObject *kwnames) -{ - int ret = 0; - if ((cyfunc->flags & __Pyx_CYFUNCTION_CCLASS) && !(cyfunc->flags & __Pyx_CYFUNCTION_STATICMETHOD)) { - if (unlikely(nargs < 1)) { - __Pyx_CyFunction_raise_type_error( - cyfunc, "needs an argument"); - return -1; - } - ret = 1; - } - if (unlikely(kwnames) && unlikely(__Pyx_PyTuple_GET_SIZE(kwnames))) { - __Pyx_CyFunction_raise_type_error( - cyfunc, "takes no keyword arguments"); - return -1; - } - return ret; -} -static PyObject * __Pyx_CyFunction_Vectorcall_NOARGS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) -{ - __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; -#if CYTHON_BACKPORT_VECTORCALL - Py_ssize_t nargs = (Py_ssize_t)nargsf; -#else - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); -#endif - PyObject *self; -#if CYTHON_COMPILING_IN_LIMITED_API - PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); - if (unlikely(!meth)) return NULL; -#else - PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; -#endif - switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { - case 1: - self = args[0]; - args += 1; - nargs -= 1; - break; - case 0: -#if CYTHON_COMPILING_IN_LIMITED_API - self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); - if (unlikely(!self) && PyErr_Occurred()) return NULL; -#else - self = ((PyCFunctionObject*)cyfunc)->m_self; -#endif - break; - default: - return NULL; - } - if (unlikely(nargs != 0)) { - __Pyx_CyFunction_raise_argument_count_error( - cyfunc, "takes no arguments", nargs); - return NULL; - } - return meth(self, NULL); -} -static PyObject * __Pyx_CyFunction_Vectorcall_O(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) -{ - __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; -#if CYTHON_BACKPORT_VECTORCALL - Py_ssize_t nargs = (Py_ssize_t)nargsf; -#else - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); -#endif - PyObject *self; -#if CYTHON_COMPILING_IN_LIMITED_API - PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); - if (unlikely(!meth)) return NULL; -#else - PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; -#endif - switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, kwnames)) { - case 1: - self = args[0]; - args += 1; - nargs -= 1; - break; - case 0: -#if CYTHON_COMPILING_IN_LIMITED_API - self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); - if (unlikely(!self) && PyErr_Occurred()) return NULL; -#else - self = ((PyCFunctionObject*)cyfunc)->m_self; -#endif - break; - default: - return NULL; - } - if (unlikely(nargs != 1)) { - __Pyx_CyFunction_raise_argument_count_error( - cyfunc, "takes exactly one argument", nargs); - return NULL; - } - return meth(self, args[0]); -} -static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) -{ - __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; -#if CYTHON_BACKPORT_VECTORCALL - Py_ssize_t nargs = (Py_ssize_t)nargsf; -#else - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); -#endif - PyObject *self; -#if CYTHON_COMPILING_IN_LIMITED_API - PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); - if (unlikely(!meth)) return NULL; -#else - PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; -#endif - switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { - case 1: - self = args[0]; - args += 1; - nargs -= 1; - break; - case 0: -#if CYTHON_COMPILING_IN_LIMITED_API - self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); - if (unlikely(!self) && PyErr_Occurred()) return NULL; -#else - self = ((PyCFunctionObject*)cyfunc)->m_self; -#endif - break; - default: - return NULL; - } - return ((__Pyx_PyCFunctionFastWithKeywords)(void(*)(void))meth)(self, args, nargs, kwnames); -} -static PyObject * __Pyx_CyFunction_Vectorcall_FASTCALL_KEYWORDS_METHOD(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) -{ - __pyx_CyFunctionObject *cyfunc = (__pyx_CyFunctionObject *)func; - PyTypeObject *cls = (PyTypeObject *) __Pyx_CyFunction_GetClassObj(cyfunc); -#if CYTHON_BACKPORT_VECTORCALL - Py_ssize_t nargs = (Py_ssize_t)nargsf; -#else - Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); -#endif - PyObject *self; -#if CYTHON_COMPILING_IN_LIMITED_API - PyCFunction meth = PyCFunction_GetFunction(cyfunc->func); - if (unlikely(!meth)) return NULL; -#else - PyCFunction meth = ((PyCFunctionObject*)cyfunc)->m_ml->ml_meth; -#endif - switch (__Pyx_CyFunction_Vectorcall_CheckArgs(cyfunc, nargs, NULL)) { - case 1: - self = args[0]; - args += 1; - nargs -= 1; - break; - case 0: -#if CYTHON_COMPILING_IN_LIMITED_API - self = PyCFunction_GetSelf(((__pyx_CyFunctionObject*)cyfunc)->func); - if (unlikely(!self) && PyErr_Occurred()) return NULL; -#else - self = ((PyCFunctionObject*)cyfunc)->m_self; -#endif - break; - default: - return NULL; - } - return ((__Pyx_PyCMethod)(void(*)(void))meth)(self, cls, args, (size_t)nargs, kwnames); -} -#endif -static PyType_Slot __pyx_CyFunctionType_slots[] = { - {Py_tp_dealloc, (void *)__Pyx_CyFunction_dealloc}, - {Py_tp_repr, (void *)__Pyx_CyFunction_repr}, - {Py_tp_call, (void *)__Pyx_CyFunction_CallAsMethod}, - {Py_tp_traverse, (void *)__Pyx_CyFunction_traverse}, - {Py_tp_clear, (void *)__Pyx_CyFunction_clear}, - {Py_tp_methods, (void *)__pyx_CyFunction_methods}, - {Py_tp_members, (void *)__pyx_CyFunction_members}, - {Py_tp_getset, (void *)__pyx_CyFunction_getsets}, - {Py_tp_descr_get, (void *)__Pyx_PyMethod_New}, - {0, 0}, -}; -static PyType_Spec __pyx_CyFunctionType_spec = { - __PYX_TYPE_MODULE_PREFIX "cython_function_or_method", - sizeof(__pyx_CyFunctionObject), - 0, -#ifdef Py_TPFLAGS_METHOD_DESCRIPTOR - Py_TPFLAGS_METHOD_DESCRIPTOR | -#endif -#if CYTHON_METH_FASTCALL -#if defined(Py_TPFLAGS_HAVE_VECTORCALL) - Py_TPFLAGS_HAVE_VECTORCALL | -#elif defined(_Py_TPFLAGS_HAVE_VECTORCALL) - _Py_TPFLAGS_HAVE_VECTORCALL | -#endif -#endif // CYTHON_METH_FASTCALL -#if PY_VERSION_HEX >= 0x030A0000 - Py_TPFLAGS_IMMUTABLETYPE | -#endif - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, - __pyx_CyFunctionType_slots -}; -static int __pyx_CyFunction_init(PyObject *module) { - __pyx_mstatetype *mstate = __Pyx_PyModule_GetState(module); - mstate->__pyx_CyFunctionType = __Pyx_FetchCommonTypeFromSpec(module, &__pyx_CyFunctionType_spec, NULL); - if (unlikely(mstate->__pyx_CyFunctionType == NULL)) { - return -1; - } - return 0; -} -static CYTHON_INLINE PyObject *__Pyx_CyFunction_InitDefaults(PyObject *func, PyTypeObject *defaults_type) { - __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; - m->defaults = PyObject_CallObject((PyObject*)defaults_type, NULL); // _PyObject_New(defaults_type); - if (unlikely(!m->defaults)) - return NULL; - return m->defaults; -} -static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsTuple(PyObject *func, PyObject *tuple) { - __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; - m->defaults_tuple = tuple; - Py_INCREF(tuple); -} -static CYTHON_INLINE void __Pyx_CyFunction_SetDefaultsKwDict(PyObject *func, PyObject *dict) { - __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; - m->defaults_kwdict = dict; - Py_INCREF(dict); -} -static CYTHON_INLINE void __Pyx_CyFunction_SetAnnotationsDict(PyObject *func, PyObject *dict) { - __pyx_CyFunctionObject *m = (__pyx_CyFunctionObject *) func; - m->func_annotations = dict; - Py_INCREF(dict); -} - -/* CythonFunction */ -static PyObject *__Pyx_CyFunction_New(PyMethodDef *ml, int flags, PyObject* qualname, - PyObject *closure, PyObject *module, PyObject* globals, PyObject* code) { - PyObject *op = __Pyx_CyFunction_Init( - PyObject_GC_New(__pyx_CyFunctionObject, __pyx_mstate_global->__pyx_CyFunctionType), - ml, flags, qualname, closure, module, globals, code - ); - if (likely(op)) { - PyObject_GC_Track(op); - } - return op; -} - -/* CalculateMetaclass */ -static PyObject *__Pyx_CalculateMetaclass(PyTypeObject *metaclass, PyObject *bases) { - Py_ssize_t i, nbases; -#if CYTHON_ASSUME_SAFE_SIZE - nbases = PyTuple_GET_SIZE(bases); -#else - nbases = PyTuple_Size(bases); - if (nbases < 0) return NULL; -#endif - for (i=0; i < nbases; i++) { - PyTypeObject *tmptype; -#if CYTHON_ASSUME_SAFE_MACROS - PyObject *tmp = PyTuple_GET_ITEM(bases, i); -#else - PyObject *tmp = PyTuple_GetItem(bases, i); - if (!tmp) return NULL; -#endif - tmptype = Py_TYPE(tmp); - if (!metaclass) { - metaclass = tmptype; - continue; - } - if (PyType_IsSubtype(metaclass, tmptype)) - continue; - if (PyType_IsSubtype(tmptype, metaclass)) { - metaclass = tmptype; - continue; - } - PyErr_SetString(PyExc_TypeError, - "metaclass conflict: " - "the metaclass of a derived class " - "must be a (non-strict) subclass " - "of the metaclasses of all its bases"); - return NULL; - } - if (!metaclass) { - metaclass = &PyType_Type; - } - Py_INCREF((PyObject*) metaclass); - return (PyObject*) metaclass; -} - -/* Py3ClassCreate */ -static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, - PyObject *qualname, PyObject *mkw, PyObject *modname, PyObject *doc) { - PyObject *ns; - if (metaclass) { - PyObject *prep = __Pyx_PyObject_GetAttrStrNoError(metaclass, __pyx_mstate_global->__pyx_n_u_prepare); - if (prep) { - PyObject *pargs[3] = {NULL, name, bases}; - ns = __Pyx_PyObject_FastCallDict(prep, pargs+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET, mkw); - Py_DECREF(prep); - } else { - if (unlikely(PyErr_Occurred())) - return NULL; - ns = PyDict_New(); - } - } else { - ns = PyDict_New(); - } - if (unlikely(!ns)) - return NULL; - if (unlikely(PyObject_SetItem(ns, __pyx_mstate_global->__pyx_n_u_module, modname) < 0)) goto bad; - if (unlikely(PyObject_SetItem(ns, __pyx_mstate_global->__pyx_n_u_qualname, qualname) < 0)) goto bad; - if (unlikely(doc && PyObject_SetItem(ns, __pyx_mstate_global->__pyx_n_u_doc, doc) < 0)) goto bad; - return ns; -bad: - Py_DECREF(ns); - return NULL; -} -static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, - PyObject *dict, PyObject *mkw, - int calculate_metaclass, int allow_py2_metaclass) { - PyObject *result; - PyObject *owned_metaclass = NULL; - PyObject *margs[4] = {NULL, name, bases, dict}; - if (allow_py2_metaclass) { - owned_metaclass = PyObject_GetItem(dict, __pyx_mstate_global->__pyx_n_u_metaclass); - if (owned_metaclass) { - metaclass = owned_metaclass; - } else if (likely(PyErr_ExceptionMatches(PyExc_KeyError))) { - PyErr_Clear(); - } else { - return NULL; - } - } - if (calculate_metaclass && (!metaclass || PyType_Check(metaclass))) { - metaclass = __Pyx_CalculateMetaclass((PyTypeObject*) metaclass, bases); - Py_XDECREF(owned_metaclass); - if (unlikely(!metaclass)) - return NULL; - owned_metaclass = metaclass; - } - result = __Pyx_PyObject_FastCallDict(metaclass, margs+1, 3 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET, mkw); - Py_XDECREF(owned_metaclass); - return result; -} - -/* CLineInTraceback */ -#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME -static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; -#if CYTHON_COMPILING_IN_CPYTHON - PyObject **cython_runtime_dict; -#endif - CYTHON_MAYBE_UNUSED_VAR(tstate); - if (unlikely(!__pyx_mstate_global->__pyx_cython_runtime)) { - return c_line; - } - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); -#if CYTHON_COMPILING_IN_CPYTHON - cython_runtime_dict = _PyObject_GetDictPtr(__pyx_mstate_global->__pyx_cython_runtime); - if (likely(cython_runtime_dict)) { - __Pyx_BEGIN_CRITICAL_SECTION(*cython_runtime_dict); - __PYX_PY_DICT_LOOKUP_IF_MODIFIED( - use_cline, *cython_runtime_dict, - __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_mstate_global->__pyx_n_u_cline_in_traceback)) - Py_XINCREF(use_cline); - __Pyx_END_CRITICAL_SECTION(); - } else -#endif - { - PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_mstate_global->__pyx_cython_runtime, __pyx_mstate_global->__pyx_n_u_cline_in_traceback); - if (use_cline_obj) { - use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; - Py_INCREF(use_cline); - Py_DECREF(use_cline_obj); - } else { - PyErr_Clear(); - use_cline = NULL; - } - } - if (!use_cline) { - c_line = 0; - (void) PyObject_SetAttr(__pyx_mstate_global->__pyx_cython_runtime, __pyx_mstate_global->__pyx_n_u_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; - } - Py_XDECREF(use_cline); - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - return c_line; -} -#endif - -/* CodeObjectCache */ -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { - int start = 0, mid = 0, end = count - 1; - if (end >= 0 && code_line > entries[end].code_line) { - return count; - } - while (start < end) { - mid = start + (end - start) / 2; - if (code_line < entries[mid].code_line) { - end = mid; - } else if (code_line > entries[mid].code_line) { - start = mid + 1; - } else { - return mid; - } - } - if (code_line <= entries[mid].code_line) { - return mid; - } else { - return mid + 1; - } -} -static __Pyx_CachedCodeObjectType *__pyx__find_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line) { - __Pyx_CachedCodeObjectType* code_object; - int pos; - if (unlikely(!code_line) || unlikely(!code_cache->entries)) { - return NULL; - } - pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); - if (unlikely(pos >= code_cache->count) || unlikely(code_cache->entries[pos].code_line != code_line)) { - return NULL; - } - code_object = code_cache->entries[pos].code_object; - Py_INCREF(code_object); - return code_object; -} -static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line) { -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS - (void)__pyx__find_code_object; - return NULL; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just miss. -#else - struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_nonatomic_int_type old_count = __pyx_atomic_incr_acq_rel(&code_cache->accessor_count); - if (old_count < 0) { - __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); - return NULL; - } -#endif - __Pyx_CachedCodeObjectType *result = __pyx__find_code_object(code_cache, code_line); -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); -#endif - return result; -#endif -} -static void __pyx__insert_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line, __Pyx_CachedCodeObjectType* code_object) -{ - int pos, i; - __Pyx_CodeObjectCacheEntry* entries = code_cache->entries; - if (unlikely(!code_line)) { - return; - } - if (unlikely(!entries)) { - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); - if (likely(entries)) { - code_cache->entries = entries; - code_cache->max_count = 64; - code_cache->count = 1; - entries[0].code_line = code_line; - entries[0].code_object = code_object; - Py_INCREF(code_object); - } - return; - } - pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); - if ((pos < code_cache->count) && unlikely(code_cache->entries[pos].code_line == code_line)) { - __Pyx_CachedCodeObjectType* tmp = entries[pos].code_object; - entries[pos].code_object = code_object; - Py_INCREF(code_object); - Py_DECREF(tmp); - return; - } - if (code_cache->count == code_cache->max_count) { - int new_max = code_cache->max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( - code_cache->entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } - code_cache->entries = entries; - code_cache->max_count = new_max; - } - for (i=code_cache->count; i>pos; i--) { - entries[i] = entries[i-1]; - } - entries[pos].code_line = code_line; - entries[pos].code_object = code_object; - code_cache->count++; - Py_INCREF(code_object); -} -static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object) { -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS - (void)__pyx__insert_code_object; - return; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just fail. -#else - struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_nonatomic_int_type expected = 0; - if (!__pyx_atomic_int_cmp_exchange(&code_cache->accessor_count, &expected, INT_MIN)) { - return; - } -#endif - __pyx__insert_code_object(code_cache, code_line, code_object); -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_sub(&code_cache->accessor_count, INT_MIN); -#endif -#endif -} - -/* AddTraceback */ -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" -#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API && !defined(PYPY_VERSION) - #ifndef Py_BUILD_CORE - #define Py_BUILD_CORE 1 - #endif - #include "internal/pycore_frame.h" -#endif -#if CYTHON_COMPILING_IN_LIMITED_API -static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, - PyObject *firstlineno, PyObject *name) { - PyObject *replace = NULL; - if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; - if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; - replace = PyObject_GetAttrString(code, "replace"); - if (likely(replace)) { - PyObject *result = PyObject_Call(replace, __pyx_mstate_global->__pyx_empty_tuple, scratch_dict); - Py_DECREF(replace); - return result; - } - PyErr_Clear(); - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; - PyObject *replace = NULL, *getframe = NULL, *frame = NULL; - PyObject *exc_type, *exc_value, *exc_traceback; - int success = 0; - if (c_line) { - (void) __pyx_cfilenm; - (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); - } - PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); - code_object = __pyx_find_code_object(c_line ? -c_line : py_line); - if (!code_object) { - code_object = Py_CompileString("_getframe()", filename, Py_eval_input); - if (unlikely(!code_object)) goto bad; - py_py_line = PyLong_FromLong(py_line); - if (unlikely(!py_py_line)) goto bad; - py_funcname = PyUnicode_FromString(funcname); - if (unlikely(!py_funcname)) goto bad; - dict = PyDict_New(); - if (unlikely(!dict)) goto bad; - { - PyObject *old_code_object = code_object; - code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); - Py_DECREF(old_code_object); - } - if (unlikely(!code_object)) goto bad; - __pyx_insert_code_object(c_line ? -c_line : py_line, code_object); - } else { - dict = PyDict_New(); - } - getframe = PySys_GetObject("_getframe"); - if (unlikely(!getframe)) goto bad; - if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; - frame = PyEval_EvalCode(code_object, dict, dict); - if (unlikely(!frame) || frame == Py_None) goto bad; - success = 1; - bad: - PyErr_Restore(exc_type, exc_value, exc_traceback); - Py_XDECREF(code_object); - Py_XDECREF(py_py_line); - Py_XDECREF(py_funcname); - Py_XDECREF(dict); - Py_XDECREF(replace); - if (success) { - PyTraceBack_Here( - (struct _frame*)frame); - } - Py_XDECREF(frame); -} -#else -static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = NULL; - PyObject *py_funcname = NULL; - if (c_line) { - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); - if (!py_funcname) goto bad; - funcname = PyUnicode_AsUTF8(py_funcname); - if (!funcname) goto bad; - } - py_code = PyCode_NewEmpty(filename, funcname, py_line); - Py_XDECREF(py_funcname); - return py_code; -bad: - Py_XDECREF(py_funcname); - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject *ptype, *pvalue, *ptraceback; - if (c_line) { - c_line = __Pyx_CLineForTraceback(tstate, c_line); - } - py_code = __pyx_find_code_object(c_line ? -c_line : py_line); - if (!py_code) { - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); - py_code = __Pyx_CreateCodeObjectForTraceback( - funcname, c_line, py_line, filename); - if (!py_code) { - /* If the code object creation fails, then we should clear the - fetched exception references and propagate the new exception */ - Py_XDECREF(ptype); - Py_XDECREF(pvalue); - Py_XDECREF(ptraceback); - goto bad; - } - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); - } - py_frame = PyFrame_New( - tstate, /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - __pyx_mstate_global->__pyx_d, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - __Pyx_PyFrame_SetLineNumber(py_frame, py_line); - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} -#endif - -/* CIntFromPyVerify */ -#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ - {\ - func_type value = func_value;\ - if (sizeof(target_type) < sizeof(func_type)) {\ - if (unlikely(value != (func_type) (target_type) value)) {\ - func_type zero = 0;\ - if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ - return (target_type) -1;\ - if (is_unsigned && unlikely(value < zero))\ - goto raise_neg_overflow;\ - else\ - goto raise_overflow;\ - }\ - }\ - return (target_type) value;\ - } - -/* CIntFromPy */ -static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (unlikely(!PyLong_Check(x))) { - long val; - PyObject *tmp = __Pyx_PyNumber_Long(x); - if (!tmp) return (long) -1; - val = __Pyx_PyLong_As_long(tmp); - Py_DECREF(tmp); - return val; - } - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - if (unlikely(__Pyx_PyLong_IsNeg(x))) { - goto raise_neg_overflow; - } else if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_DigitCount(x)) { - case 2: - if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { - return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: - if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { - return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: - if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { - return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - } - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if ((sizeof(long) <= sizeof(unsigned long))) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_SignedDigitCount(x)) { - case -2: - if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: - if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: - if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: - if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: - if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: - if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { - return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - } -#endif - if ((sizeof(long) <= sizeof(long))) { - __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { - long val; - int ret = -1; -#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API - Py_ssize_t bytes_copied = PyLong_AsNativeBytes( - x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); - if (unlikely(bytes_copied == -1)) { - } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { - goto raise_overflow; - } else { - ret = 0; - } -#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - ret = _PyLong_AsByteArray((PyLongObject *)x, - bytes, sizeof(val), - is_little, !is_unsigned); -#else - PyObject *v; - PyObject *stepval = NULL, *mask = NULL, *shift = NULL; - int bits, remaining_bits, is_negative = 0; - int chunk_size = (sizeof(long) < 8) ? 30 : 62; - if (likely(PyLong_CheckExact(x))) { - v = __Pyx_NewRef(x); - } else { - v = PyNumber_Long(x); - if (unlikely(!v)) return (long) -1; - assert(PyLong_CheckExact(v)); - } - { - int result = PyObject_RichCompareBool(v, Py_False, Py_LT); - if (unlikely(result < 0)) { - Py_DECREF(v); - return (long) -1; - } - is_negative = result == 1; - } - if (is_unsigned && unlikely(is_negative)) { - Py_DECREF(v); - goto raise_neg_overflow; - } else if (is_negative) { - stepval = PyNumber_Invert(v); - Py_DECREF(v); - if (unlikely(!stepval)) - return (long) -1; - } else { - stepval = v; - } - v = NULL; - val = (long) 0; - mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; - shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; - for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { - PyObject *tmp, *digit; - long idigit; - digit = PyNumber_And(stepval, mask); - if (unlikely(!digit)) goto done; - idigit = PyLong_AsLong(digit); - Py_DECREF(digit); - if (unlikely(idigit < 0)) goto done; - val |= ((long) idigit) << bits; - tmp = PyNumber_Rshift(stepval, shift); - if (unlikely(!tmp)) goto done; - Py_DECREF(stepval); stepval = tmp; - } - Py_DECREF(shift); shift = NULL; - Py_DECREF(mask); mask = NULL; - { - long idigit = PyLong_AsLong(stepval); - if (unlikely(idigit < 0)) goto done; - remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); - if (unlikely(idigit >= (1L << remaining_bits))) - goto raise_overflow; - val |= ((long) idigit) << bits; - } - if (!is_unsigned) { - if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) - goto raise_overflow; - if (is_negative) - val = ~val; - } - ret = 0; - done: - Py_XDECREF(shift); - Py_XDECREF(mask); - Py_XDECREF(stepval); -#endif - if (unlikely(ret)) - return (long) -1; - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to long"); - return (long) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long) -1; -} - -/* PyObjectVectorCallKwBuilder */ -#if CYTHON_VECTORCALL -static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - (void)__Pyx_PyObject_FastCallDict; - if (__Pyx_PyTuple_SET_ITEM(builder, n, key) != (0)) return -1; - Py_INCREF(key); - args[n] = value; - return 0; -} -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - (void)__Pyx_VectorcallBuilder_AddArgStr; - if (unlikely(!PyUnicode_Check(key))) { - PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return -1; - } - return __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n); -} -static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - PyObject *pyKey = PyUnicode_FromString(key); - if (!pyKey) return -1; - return __Pyx_VectorcallBuilder_AddArg(pyKey, value, builder, args, n); -} -#else // CYTHON_VECTORCALL -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, CYTHON_UNUSED PyObject **args, CYTHON_UNUSED int n) { - if (unlikely(!PyUnicode_Check(key))) { - PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return -1; - } - return PyDict_SetItem(builder, key, value); -} -#endif - -/* CIntToPy */ -static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { - return PyLong_FromLong((long) value); - } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -#endif - } - } else { - if (sizeof(long) <= sizeof(long)) { - return PyLong_FromLong((long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); -#endif - } - } - { - unsigned char *bytes = (unsigned char *)&value; -#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 - if (is_unsigned) { - return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); - } else { - return PyLong_FromNativeBytes(bytes, sizeof(value), -1); - } -#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 - int one = 1; int little = (int)*(unsigned char *)&one; - return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); -#else - int one = 1; int little = (int)*(unsigned char *)&one; - PyObject *from_bytes, *result = NULL, *kwds = NULL; - PyObject *py_bytes = NULL, *order_str = NULL; - from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); - if (!from_bytes) return NULL; - py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); - if (!py_bytes) goto limited_bad; - order_str = PyUnicode_FromString(little ? "little" : "big"); - if (!order_str) goto limited_bad; - { - PyObject *args[3+(CYTHON_VECTORCALL ? 1 : 0)] = { NULL, py_bytes, order_str }; - if (!is_unsigned) { - kwds = __Pyx_MakeVectorcallBuilderKwds(1); - if (!kwds) goto limited_bad; - if (__Pyx_VectorcallBuilder_AddArgStr("signed", __Pyx_NewRef(Py_True), kwds, args+3, 0) < 0) goto limited_bad; - } - result = __Pyx_Object_Vectorcall_CallFromBuilder(from_bytes, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET, kwds); - } - limited_bad: - Py_XDECREF(kwds); - Py_XDECREF(order_str); - Py_XDECREF(py_bytes); - Py_XDECREF(from_bytes); - return result; -#endif - } -} - -/* FormatTypeName */ -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030d0000 -static __Pyx_TypeName -__Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp) -{ - PyObject *module = NULL, *name = NULL, *result = NULL; - #if __PYX_LIMITED_VERSION_HEX < 0x030b0000 - name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, - __pyx_mstate_global->__pyx_n_u_qualname); - #else - name = PyType_GetQualName(tp); - #endif - if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) goto bad; - module = __Pyx_PyObject_GetAttrStr((PyObject *)tp, - __pyx_mstate_global->__pyx_n_u_module); - if (unlikely(module == NULL) || unlikely(!PyUnicode_Check(module))) goto bad; - if (PyUnicode_CompareWithASCIIString(module, "builtins") == 0) { - result = name; - name = NULL; - goto done; - } - result = PyUnicode_FromFormat("%U.%U", module, name); - if (unlikely(result == NULL)) goto bad; - done: - Py_XDECREF(name); - Py_XDECREF(module); - return result; - bad: - PyErr_Clear(); - if (name) { - result = name; - name = NULL; - } else { - result = __Pyx_NewRef(__pyx_mstate_global->__pyx_kp_u__5); - } - goto done; -} -#endif - -/* CIntFromPy */ -static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const int neg_one = (int) -1, const_zero = (int) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (unlikely(!PyLong_Check(x))) { - int val; - PyObject *tmp = __Pyx_PyNumber_Long(x); - if (!tmp) return (int) -1; - val = __Pyx_PyLong_As_int(tmp); - Py_DECREF(tmp); - return val; - } - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - if (unlikely(__Pyx_PyLong_IsNeg(x))) { - goto raise_neg_overflow; - } else if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_DigitCount(x)) { - case 2: - if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { - return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: - if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { - return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: - if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { - return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - } - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if ((sizeof(int) <= sizeof(unsigned long))) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_SignedDigitCount(x)) { - case -2: - if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: - if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: - if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: - if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: - if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: - if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { - return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - } -#endif - if ((sizeof(int) <= sizeof(long))) { - __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { - int val; - int ret = -1; -#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API - Py_ssize_t bytes_copied = PyLong_AsNativeBytes( - x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); - if (unlikely(bytes_copied == -1)) { - } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { - goto raise_overflow; - } else { - ret = 0; - } -#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - ret = _PyLong_AsByteArray((PyLongObject *)x, - bytes, sizeof(val), - is_little, !is_unsigned); -#else - PyObject *v; - PyObject *stepval = NULL, *mask = NULL, *shift = NULL; - int bits, remaining_bits, is_negative = 0; - int chunk_size = (sizeof(long) < 8) ? 30 : 62; - if (likely(PyLong_CheckExact(x))) { - v = __Pyx_NewRef(x); - } else { - v = PyNumber_Long(x); - if (unlikely(!v)) return (int) -1; - assert(PyLong_CheckExact(v)); - } - { - int result = PyObject_RichCompareBool(v, Py_False, Py_LT); - if (unlikely(result < 0)) { - Py_DECREF(v); - return (int) -1; - } - is_negative = result == 1; - } - if (is_unsigned && unlikely(is_negative)) { - Py_DECREF(v); - goto raise_neg_overflow; - } else if (is_negative) { - stepval = PyNumber_Invert(v); - Py_DECREF(v); - if (unlikely(!stepval)) - return (int) -1; - } else { - stepval = v; - } - v = NULL; - val = (int) 0; - mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; - shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; - for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { - PyObject *tmp, *digit; - long idigit; - digit = PyNumber_And(stepval, mask); - if (unlikely(!digit)) goto done; - idigit = PyLong_AsLong(digit); - Py_DECREF(digit); - if (unlikely(idigit < 0)) goto done; - val |= ((int) idigit) << bits; - tmp = PyNumber_Rshift(stepval, shift); - if (unlikely(!tmp)) goto done; - Py_DECREF(stepval); stepval = tmp; - } - Py_DECREF(shift); shift = NULL; - Py_DECREF(mask); mask = NULL; - { - long idigit = PyLong_AsLong(stepval); - if (unlikely(idigit < 0)) goto done; - remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); - if (unlikely(idigit >= (1L << remaining_bits))) - goto raise_overflow; - val |= ((int) idigit) << bits; - } - if (!is_unsigned) { - if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) - goto raise_overflow; - if (is_negative) - val = ~val; - } - ret = 0; - done: - Py_XDECREF(shift); - Py_XDECREF(mask); - Py_XDECREF(stepval); -#endif - if (unlikely(ret)) - return (int) -1; - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to int"); - return (int) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to int"); - return (int) -1; -} - -/* FastTypeChecks */ -#if CYTHON_COMPILING_IN_CPYTHON -static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { - while (a) { - a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); - if (a == b) - return 1; - } - return b == &PyBaseObject_Type; -} -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { - PyObject *mro; - if (a == b) return 1; - mro = a->tp_mro; - if (likely(mro)) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) - return 1; - } - return 0; - } - return __Pyx_InBases(a, b); -} -static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { - PyObject *mro; - if (cls == a || cls == b) return 1; - mro = cls->tp_mro; - if (likely(mro)) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - PyObject *base = PyTuple_GET_ITEM(mro, i); - if (base == (PyObject *)a || base == (PyObject *)b) - return 1; - } - return 0; - } - return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); -} -static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { - if (exc_type1) { - return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); - } else { - return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); - } -} -static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - assert(PyExceptionClass_Check(exc_type)); - n = PyTuple_GET_SIZE(tuple); - for (i=0; i= 0x030b0000 - return Py_Version & ~0xFFUL; -#else - static unsigned long __Pyx_cached_runtime_version = 0; - if (__Pyx_cached_runtime_version == 0) { - const char* rt_version = Py_GetVersion(); - unsigned long version = 0; - unsigned long factor = 0x01000000UL; - unsigned int digit = 0; - int i = 0; - while (factor) { - while ('0' <= rt_version[i] && rt_version[i] <= '9') { - digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); - ++i; - } - version += factor * digit; - if (rt_version[i] != '.') - break; - digit = 0; - factor >>= 8; - ++i; - } - __Pyx_cached_runtime_version = version; - } - return __Pyx_cached_runtime_version; -#endif -} - -/* CheckBinaryVersion */ -static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { - const unsigned long MAJOR_MINOR = 0xFFFF0000UL; - if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) - return 0; - if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) - return 1; - { - char message[200]; - PyOS_snprintf(message, sizeof(message), - "compile time Python version %d.%d " - "of module '%.100s' " - "%s " - "runtime version %d.%d", - (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), - __Pyx_MODULE_NAME, - (allow_newer) ? "was newer than" : "does not match", - (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) - ); - return PyErr_WarnEx(NULL, message, 1); - } -} - -/* NewCodeObj */ -#if CYTHON_COMPILING_IN_LIMITED_API - static PyObject* __Pyx__PyCode_New(int a, int p, int k, int l, int s, int f, - PyObject *code, PyObject *c, PyObject* n, PyObject *v, - PyObject *fv, PyObject *cell, PyObject* fn, - PyObject *name, int fline, PyObject *lnos) { - PyObject *exception_table = NULL; - PyObject *types_module=NULL, *code_type=NULL, *result=NULL; - #if __PYX_LIMITED_VERSION_HEX < 0x030b0000 - PyObject *version_info; - PyObject *py_minor_version = NULL; - #endif - long minor_version = 0; - PyObject *type, *value, *traceback; - PyErr_Fetch(&type, &value, &traceback); - #if __PYX_LIMITED_VERSION_HEX >= 0x030b0000 - minor_version = 11; - #else - if (!(version_info = PySys_GetObject("version_info"))) goto end; - if (!(py_minor_version = PySequence_GetItem(version_info, 1))) goto end; - minor_version = PyLong_AsLong(py_minor_version); - Py_DECREF(py_minor_version); - if (minor_version == -1 && PyErr_Occurred()) goto end; - #endif - if (!(types_module = PyImport_ImportModule("types"))) goto end; - if (!(code_type = PyObject_GetAttrString(types_module, "CodeType"))) goto end; - if (minor_version <= 7) { - (void)p; - result = PyObject_CallFunction(code_type, "iiiiiOOOOOOiOOO", a, k, l, s, f, code, - c, n, v, fn, name, fline, lnos, fv, cell); - } else if (minor_version <= 10) { - result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOiOOO", a,p, k, l, s, f, code, - c, n, v, fn, name, fline, lnos, fv, cell); - } else { - if (!(exception_table = PyBytes_FromStringAndSize(NULL, 0))) goto end; - result = PyObject_CallFunction(code_type, "iiiiiiOOOOOOOiOOOO", a,p, k, l, s, f, code, - c, n, v, fn, name, name, fline, lnos, exception_table, fv, cell); - } - end: - Py_XDECREF(code_type); - Py_XDECREF(exception_table); - Py_XDECREF(types_module); - if (type) { - PyErr_Restore(type, value, traceback); - } - return result; - } -#elif PY_VERSION_HEX >= 0x030B0000 - static PyCodeObject* __Pyx__PyCode_New(int a, int p, int k, int l, int s, int f, - PyObject *code, PyObject *c, PyObject* n, PyObject *v, - PyObject *fv, PyObject *cell, PyObject* fn, - PyObject *name, int fline, PyObject *lnos) { - PyCodeObject *result; - result = - #if PY_VERSION_HEX >= 0x030C0000 - PyUnstable_Code_NewWithPosOnlyArgs - #else - PyCode_NewWithPosOnlyArgs - #endif - (a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, __pyx_mstate_global->__pyx_empty_bytes); - return result; - } -#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY - #define __Pyx__PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_NewWithPosOnlyArgs(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -#else - #define __Pyx__PyCode_New(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ - PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) -#endif -static PyObject* __Pyx_PyCode_New( - __Pyx_PyCode_New_function_description descr, - PyObject **varnames, - PyObject* filename, - PyObject *funcname, - const char *line_table, - PyObject *tuple_dedup_map -) { - PyObject *code_obj = NULL, *varnames_tuple_dedup = NULL, *code_bytes = NULL, *line_table_bytes = NULL; - Py_ssize_t var_count = (Py_ssize_t) descr.nlocals; - PyObject *varnames_tuple = PyTuple_New(var_count); - if (unlikely(!varnames_tuple)) return NULL; - for (Py_ssize_t i=0; i < var_count; i++) { - Py_INCREF(varnames[i]); - if (__Pyx_PyTuple_SET_ITEM(varnames_tuple, i, varnames[i]) != (0)) goto done; - } - #if CYTHON_COMPILING_IN_LIMITED_API - varnames_tuple_dedup = PyDict_GetItem(tuple_dedup_map, varnames_tuple); - if (!varnames_tuple_dedup) { - if (unlikely(PyDict_SetItem(tuple_dedup_map, varnames_tuple, varnames_tuple) < 0)) goto done; - varnames_tuple_dedup = varnames_tuple; - } - #else - varnames_tuple_dedup = PyDict_SetDefault(tuple_dedup_map, varnames_tuple, varnames_tuple); - if (unlikely(!varnames_tuple_dedup)) goto done; - #endif - #if CYTHON_AVOID_BORROWED_REFS - Py_INCREF(varnames_tuple_dedup); - #endif - if (__PYX_LIMITED_VERSION_HEX >= (0x030b0000) && line_table != NULL - && !CYTHON_COMPILING_IN_GRAAL) { - line_table_bytes = PyBytes_FromStringAndSize(line_table, descr.line_table_length); - if (unlikely(!line_table_bytes)) goto done; - Py_ssize_t code_len = (descr.line_table_length * 2 + 4) & ~3; - code_bytes = PyBytes_FromStringAndSize(NULL, code_len); - if (unlikely(!code_bytes)) goto done; - char* c_code_bytes = PyBytes_AsString(code_bytes); - if (unlikely(!c_code_bytes)) goto done; - memset(c_code_bytes, 0, (size_t) code_len); - } - code_obj = (PyObject*) __Pyx__PyCode_New( - (int) descr.argcount, - (int) descr.num_posonly_args, - (int) descr.num_kwonly_args, - (int) descr.nlocals, - 0, - (int) descr.flags, - code_bytes ? code_bytes : __pyx_mstate_global->__pyx_empty_bytes, - __pyx_mstate_global->__pyx_empty_tuple, - __pyx_mstate_global->__pyx_empty_tuple, - varnames_tuple_dedup, - __pyx_mstate_global->__pyx_empty_tuple, - __pyx_mstate_global->__pyx_empty_tuple, - filename, - funcname, - (int) descr.first_line, - (__PYX_LIMITED_VERSION_HEX >= (0x030b0000) && line_table_bytes) ? line_table_bytes : __pyx_mstate_global->__pyx_empty_bytes - ); -done: - Py_XDECREF(code_bytes); - Py_XDECREF(line_table_bytes); - #if CYTHON_AVOID_BORROWED_REFS - Py_XDECREF(varnames_tuple_dedup); - #endif - Py_DECREF(varnames_tuple); - return code_obj; -} - -/* InitStrings */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry const *t, PyObject **target, const char* const* encoding_names) { - while (t->s) { - PyObject *str; - if (t->is_unicode) { - if (t->intern) { - str = PyUnicode_InternFromString(t->s); - } else if (t->encoding) { - str = PyUnicode_Decode(t->s, t->n - 1, encoding_names[t->encoding], NULL); - } else { - str = PyUnicode_FromStringAndSize(t->s, t->n - 1); - } - } else { - str = PyBytes_FromStringAndSize(t->s, t->n - 1); - } - if (!str) - return -1; - *target = str; - if (PyObject_Hash(str) == -1) - return -1; - ++t; - ++target; - } - return 0; -} - -#include -static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { - size_t len = strlen(s); - if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { - PyErr_SetString(PyExc_OverflowError, "byte string is too long"); - return -1; - } - return (Py_ssize_t) len; -} -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { - Py_ssize_t len = __Pyx_ssize_strlen(c_str); - if (unlikely(len < 0)) return NULL; - return __Pyx_PyUnicode_FromStringAndSize(c_str, len); -} -static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { - Py_ssize_t len = __Pyx_ssize_strlen(c_str); - if (unlikely(len < 0)) return NULL; - return PyByteArray_FromStringAndSize(c_str, len); -} -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { - Py_ssize_t ignore; - return __Pyx_PyObject_AsStringAndSize(o, &ignore); -} -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 -static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { - if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; -#if CYTHON_COMPILING_IN_LIMITED_API - { - const char* result; - Py_ssize_t unicode_length; - CYTHON_MAYBE_UNUSED_VAR(unicode_length); // only for __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - #if __PYX_LIMITED_VERSION_HEX < 0x030A0000 - if (unlikely(PyArg_Parse(o, "s#", &result, length) < 0)) return NULL; - #else - result = PyUnicode_AsUTF8AndSize(o, length); - #endif - #if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - unicode_length = PyUnicode_GetLength(o); - if (unlikely(unicode_length < 0)) return NULL; - if (unlikely(unicode_length != *length)) { - PyUnicode_AsASCIIString(o); - return NULL; - } - #endif - return result; - } -#else -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - if (likely(PyUnicode_IS_ASCII(o))) { - *length = PyUnicode_GET_LENGTH(o); - return PyUnicode_AsUTF8(o); - } else { - PyUnicode_AsASCIIString(o); - return NULL; - } -#else - return PyUnicode_AsUTF8AndSize(o, length); -#endif -#endif -} -#endif -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 - if (PyUnicode_Check(o)) { - return __Pyx_PyUnicode_AsStringAndSize(o, length); - } else -#endif - if (PyByteArray_Check(o)) { -#if (CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS) || (CYTHON_COMPILING_IN_PYPY && (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE))) - *length = PyByteArray_GET_SIZE(o); - return PyByteArray_AS_STRING(o); -#else - *length = PyByteArray_Size(o); - if (*length == -1) return NULL; - return PyByteArray_AsString(o); -#endif - } else - { - char* result; - int r = PyBytes_AsStringAndSize(o, &result, length); - if (unlikely(r < 0)) { - return NULL; - } else { - return result; - } - } -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - int is_true = x == Py_True; - if (is_true | (x == Py_False) | (x == Py_None)) return is_true; - else return PyObject_IsTrue(x); -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { - int retval; - if (unlikely(!x)) return -1; - retval = __Pyx_PyObject_IsTrue(x); - Py_DECREF(x); - return retval; -} -static PyObject* __Pyx_PyNumber_LongWrongResultType(PyObject* result) { - __Pyx_TypeName result_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(result)); - if (PyLong_Check(result)) { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " - "The ability to return an instance of a strict subclass of int is deprecated, " - "and may be removed in a future version of Python.", - result_type_name)) { - __Pyx_DECREF_TypeName(result_type_name); - Py_DECREF(result); - return NULL; - } - __Pyx_DECREF_TypeName(result_type_name); - return result; - } - PyErr_Format(PyExc_TypeError, - "__int__ returned non-int (type " __Pyx_FMT_TYPENAME ")", - result_type_name); - __Pyx_DECREF_TypeName(result_type_name); - Py_DECREF(result); - return NULL; -} -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x) { -#if CYTHON_USE_TYPE_SLOTS - PyNumberMethods *m; -#endif - PyObject *res = NULL; - if (likely(PyLong_Check(x))) - return __Pyx_NewRef(x); -#if CYTHON_USE_TYPE_SLOTS - m = Py_TYPE(x)->tp_as_number; - if (likely(m && m->nb_int)) { - res = m->nb_int(x); - } -#else - if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { - res = PyNumber_Long(x); - } -#endif - if (likely(res)) { - if (unlikely(!PyLong_CheckExact(res))) { - return __Pyx_PyNumber_LongWrongResultType(res); - } - } - else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "an integer is required"); - } - return res; -} -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject *x; - if (likely(PyLong_CheckExact(b))) { - #if CYTHON_USE_PYLONG_INTERNALS - if (likely(__Pyx_PyLong_IsCompact(b))) { - return __Pyx_PyLong_CompactValue(b); - } else { - const digit* digits = __Pyx_PyLong_Digits(b); - const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); - switch (size) { - case 2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - } - } - #endif - return PyLong_AsSsize_t(b); - } - x = PyNumber_Index(b); - if (!x) return -1; - ival = PyLong_AsSsize_t(x); - Py_DECREF(x); - return ival; -} -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { - if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { - return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); - } else { - Py_ssize_t ival; - PyObject *x; - x = PyNumber_Index(o); - if (!x) return -1; - ival = PyLong_AsLong(x); - Py_DECREF(x); - return ival; - } -} -static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b) { - CYTHON_UNUSED_VAR(b); - return __Pyx_NewRef(Py_None); -} -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); -} -static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t ival) { - return PyLong_FromSize_t(ival); -} - - -/* MultiPhaseInitModuleState */ -#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE -#ifndef CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -#if (CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX >= 0x030C0000) - #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 1 -#else - #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 0 -#endif -#endif -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE && !CYTHON_ATOMICS -#error "Module state with PEP489 requires atomics. Currently that's one of\ - C11, C++11, gcc atomic intrinsics or MSVC atomic intrinsics" -#endif -#if !CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -#define __Pyx_ModuleStateLookup_Lock() -#define __Pyx_ModuleStateLookup_Unlock() -#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d0000 -static PyMutex __Pyx_ModuleStateLookup_mutex = {0}; -#define __Pyx_ModuleStateLookup_Lock() PyMutex_Lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() PyMutex_Unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(__cplusplus) && __cplusplus >= 201103L -#include -static std::mutex __Pyx_ModuleStateLookup_mutex; -#define __Pyx_ModuleStateLookup_Lock() __Pyx_ModuleStateLookup_mutex.lock() -#define __Pyx_ModuleStateLookup_Unlock() __Pyx_ModuleStateLookup_mutex.unlock() -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201112L) && !defined(__STDC_NO_THREADS__) -#include -static mtx_t __Pyx_ModuleStateLookup_mutex; -static once_flag __Pyx_ModuleStateLookup_mutex_once_flag = ONCE_FLAG_INIT; -static void __Pyx_ModuleStateLookup_initialize_mutex(void) { - mtx_init(&__Pyx_ModuleStateLookup_mutex, mtx_plain); -} -#define __Pyx_ModuleStateLookup_Lock()\ - call_once(&__Pyx_ModuleStateLookup_mutex_once_flag, __Pyx_ModuleStateLookup_initialize_mutex);\ - mtx_lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() mtx_unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(HAVE_PTHREAD_H) -#include -static pthread_mutex_t __Pyx_ModuleStateLookup_mutex = PTHREAD_MUTEX_INITIALIZER; -#define __Pyx_ModuleStateLookup_Lock() pthread_mutex_lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() pthread_mutex_unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(_WIN32) -#include // synchapi.h on its own doesn't work -static SRWLOCK __Pyx_ModuleStateLookup_mutex = SRWLOCK_INIT; -#define __Pyx_ModuleStateLookup_Lock() AcquireSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() ReleaseSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) -#else -#error "No suitable lock available for CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE.\ - Requires C standard >= C11, or C++ standard >= C++11,\ - or pthreads, or the Windows 32 API, or Python >= 3.13." -#endif -typedef struct { - int64_t id; - PyObject *module; -} __Pyx_InterpreterIdAndModule; -typedef struct { - char interpreter_id_as_index; - Py_ssize_t count; - Py_ssize_t allocated; - __Pyx_InterpreterIdAndModule table[1]; -} __Pyx_ModuleStateLookupData; -#define __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE 32 -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static __pyx_atomic_int_type __Pyx_ModuleStateLookup_read_counter = 0; -#endif -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static __pyx_atomic_ptr_type __Pyx_ModuleStateLookup_data = 0; -#else -static __Pyx_ModuleStateLookupData* __Pyx_ModuleStateLookup_data = NULL; -#endif -static __Pyx_InterpreterIdAndModule* __Pyx_State_FindModuleStateLookupTableLowerBound( - __Pyx_InterpreterIdAndModule* table, - Py_ssize_t count, - int64_t interpreterId) { - __Pyx_InterpreterIdAndModule* begin = table; - __Pyx_InterpreterIdAndModule* end = begin + count; - if (begin->id == interpreterId) { - return begin; - } - while ((end - begin) > __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { - __Pyx_InterpreterIdAndModule* halfway = begin + (end - begin)/2; - if (halfway->id == interpreterId) { - return halfway; - } - if (halfway->id < interpreterId) { - begin = halfway; - } else { - end = halfway; - } - } - for (; begin < end; ++begin) { - if (begin->id >= interpreterId) return begin; - } - return begin; -} -static PyObject *__Pyx_State_FindModule(CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return NULL; -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData* data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); - { - __pyx_atomic_incr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); - if (likely(data)) { - __Pyx_ModuleStateLookupData* new_data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_acquire(&__Pyx_ModuleStateLookup_data); - if (likely(data == new_data)) { - goto read_finished; - } - } - __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); - __Pyx_ModuleStateLookup_Lock(); - __pyx_atomic_incr_relaxed(&__Pyx_ModuleStateLookup_read_counter); - data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); - __Pyx_ModuleStateLookup_Unlock(); - } - read_finished:; -#else - __Pyx_ModuleStateLookupData* data = __Pyx_ModuleStateLookup_data; -#endif - __Pyx_InterpreterIdAndModule* found = NULL; - if (unlikely(!data)) goto end; - if (data->interpreter_id_as_index) { - if (interpreter_id < data->count) { - found = data->table+interpreter_id; - } - } else { - found = __Pyx_State_FindModuleStateLookupTableLowerBound( - data->table, data->count, interpreter_id); - } - end: - { - PyObject *result=NULL; - if (found && found->id == interpreter_id) { - result = found->module; - } -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); -#endif - return result; - } -} -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static void __Pyx_ModuleStateLookup_wait_until_no_readers(void) { - while (__pyx_atomic_load(&__Pyx_ModuleStateLookup_read_counter) != 0); -} -#else -#define __Pyx_ModuleStateLookup_wait_until_no_readers() -#endif -static int __Pyx_State_AddModuleInterpIdAsIndex(__Pyx_ModuleStateLookupData **old_data, PyObject* module, int64_t interpreter_id) { - Py_ssize_t to_allocate = (*old_data)->allocated; - while (to_allocate <= interpreter_id) { - if (to_allocate == 0) to_allocate = 1; - else to_allocate *= 2; - } - __Pyx_ModuleStateLookupData *new_data = *old_data; - if (to_allocate != (*old_data)->allocated) { - new_data = (__Pyx_ModuleStateLookupData *)realloc( - *old_data, - sizeof(__Pyx_ModuleStateLookupData)+(to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); - if (!new_data) { - PyErr_NoMemory(); - return -1; - } - for (Py_ssize_t i = new_data->allocated; i < to_allocate; ++i) { - new_data->table[i].id = i; - new_data->table[i].module = NULL; - } - new_data->allocated = to_allocate; - } - new_data->table[interpreter_id].module = module; - if (new_data->count < interpreter_id+1) { - new_data->count = interpreter_id+1; - } - *old_data = new_data; - return 0; -} -static void __Pyx_State_ConvertFromInterpIdAsIndex(__Pyx_ModuleStateLookupData *data) { - __Pyx_InterpreterIdAndModule *read = data->table; - __Pyx_InterpreterIdAndModule *write = data->table; - __Pyx_InterpreterIdAndModule *end = read + data->count; - for (; readmodule) { - write->id = read->id; - write->module = read->module; - ++write; - } - } - data->count = write - data->table; - for (; writeid = 0; - write->module = NULL; - } - data->interpreter_id_as_index = 0; -} -static int __Pyx_State_AddModule(PyObject* module, CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return -1; - int result = 0; - __Pyx_ModuleStateLookup_Lock(); -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData *old_data = (__Pyx_ModuleStateLookupData *) - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); -#else - __Pyx_ModuleStateLookupData *old_data = __Pyx_ModuleStateLookup_data; -#endif - __Pyx_ModuleStateLookupData *new_data = old_data; - if (!new_data) { - new_data = (__Pyx_ModuleStateLookupData *)calloc(1, sizeof(__Pyx_ModuleStateLookupData)); - if (!new_data) { - result = -1; - PyErr_NoMemory(); - goto end; - } - new_data->allocated = 1; - new_data->interpreter_id_as_index = 1; - } - __Pyx_ModuleStateLookup_wait_until_no_readers(); - if (new_data->interpreter_id_as_index) { - if (interpreter_id < __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { - result = __Pyx_State_AddModuleInterpIdAsIndex(&new_data, module, interpreter_id); - goto end; - } - __Pyx_State_ConvertFromInterpIdAsIndex(new_data); - } - { - Py_ssize_t insert_at = 0; - { - __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( - new_data->table, new_data->count, interpreter_id); - assert(lower_bound); - insert_at = lower_bound - new_data->table; - if (unlikely(insert_at < new_data->count && lower_bound->id == interpreter_id)) { - lower_bound->module = module; - goto end; // already in table, nothing more to do - } - } - if (new_data->count+1 >= new_data->allocated) { - Py_ssize_t to_allocate = (new_data->count+1)*2; - new_data = - (__Pyx_ModuleStateLookupData*)realloc( - new_data, - sizeof(__Pyx_ModuleStateLookupData) + - (to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); - if (!new_data) { - result = -1; - new_data = old_data; - PyErr_NoMemory(); - goto end; - } - new_data->allocated = to_allocate; - } - ++new_data->count; - int64_t last_id = interpreter_id; - PyObject *last_module = module; - for (Py_ssize_t i=insert_at; icount; ++i) { - int64_t current_id = new_data->table[i].id; - new_data->table[i].id = last_id; - last_id = current_id; - PyObject *current_module = new_data->table[i].module; - new_data->table[i].module = last_module; - last_module = current_module; - } - } - end: -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, new_data); -#else - __Pyx_ModuleStateLookup_data = new_data; -#endif - __Pyx_ModuleStateLookup_Unlock(); - return result; -} -static int __Pyx_State_RemoveModule(CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return -1; - __Pyx_ModuleStateLookup_Lock(); -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData *data = (__Pyx_ModuleStateLookupData *) - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); -#else - __Pyx_ModuleStateLookupData *data = __Pyx_ModuleStateLookup_data; -#endif - if (data->interpreter_id_as_index) { - if (interpreter_id < data->count) { - data->table[interpreter_id].module = NULL; - } - goto done; - } - { - __Pyx_ModuleStateLookup_wait_until_no_readers(); - __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( - data->table, data->count, interpreter_id); - if (!lower_bound) goto done; - if (lower_bound->id != interpreter_id) goto done; - __Pyx_InterpreterIdAndModule *end = data->table+data->count; - for (;lower_boundid = (lower_bound+1)->id; - lower_bound->module = (lower_bound+1)->module; - } - } - --data->count; - if (data->count == 0) { - free(data); - data = NULL; - } - done: -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, data); -#else - __Pyx_ModuleStateLookup_data = data; -#endif - __Pyx_ModuleStateLookup_Unlock(); - return 0; -} -#endif - -/* #### Code section: utility_code_pragmas_end ### */ -#ifdef _MSC_VER -#pragma warning( pop ) -#endif - - - -/* #### Code section: end ### */ -#endif /* Py_PYTHON_H */ diff --git a/epanet/epanet.py b/epanet/epanet.py deleted file mode 100644 index 82863d5..0000000 --- a/epanet/epanet.py +++ /dev/null @@ -1,344 +0,0 @@ -import ctypes -import platform -import os -import sys -import json -import base64 -from datetime import datetime -import subprocess -import logging -from typing import Any -sys.path.append("..") -from api import project -from api import inp_out - - -def _verify_platform(): - _platform = platform.system() - if _platform != "Windows": - raise Exception(f'Platform {_platform} unsupported (not yet)') - - -if __name__ == '__main__': - _verify_platform() - - -class Output: - def __init__(self, path: str) -> None: - self._path = path - - self._lib = ctypes.CDLL(os.path.join(os.getcwd(), 'epanet', 'epanet-output.dll')) - - self._handle = ctypes.c_void_p() - self._check(self._lib.ENR_init(ctypes.byref(self._handle))) - - self._check(self._lib.ENR_open(self._handle, ctypes.c_char_p(self._path.encode()))) - - - def __del__(self): - # throw exception in destructor ? :) - self._check(self._lib.ENR_close(ctypes.byref(self._handle))) - - - def _check(self, result): - if result != 0 and result != 10: - msg = ctypes.c_char_p() - code = self._lib.ENR_checkError(self._handle, ctypes.byref(msg)) - assert code == result - - error = f'Failed to read project [{self._path}] output, message [{msg.value.decode()}]' - - self._lib.ENR_free(ctypes.byref(msg)) - - raise Exception(error) - - - def version(self) -> int: - v = ctypes.c_int() - self._check(self._lib.ENR_getVersion(self._handle, ctypes.byref(v))) - return v.value - - - def net_size(self) -> dict[str, int]: - element_count = ctypes.POINTER(ctypes.c_int)() - length = ctypes.c_int() - self._check(self._lib.ENR_getNetSize(self._handle, ctypes.byref(element_count), ctypes.byref(length))) - assert length.value == 5 - category = ['node', 'tank', 'link', 'pump', 'valve'] - sizes = {} - for i in range(length.value): - sizes[category[i]] = element_count[i] - self._lib.ENR_free(ctypes.byref(element_count)) - return sizes - - - def units(self) -> dict[str, str]: - f_us = ['CFS', 'GPM', 'MGD', 'IMGD', 'AFD', 'LPS', 'LPM', 'MLD', 'CMH', 'CMD'] - p_us = ['PSI', 'MTR', 'KPA'] - q_us = ['NONE', 'MGL', 'UGL', 'HOURS', 'PRCNT'] - f, p, q = ctypes.c_int(1), ctypes.c_int(2), ctypes.c_int(3) - f_u, p_u, q_u = ctypes.c_int(), ctypes.c_int(), ctypes.c_int() - self._check(self._lib.ENR_getUnits(self._handle, f, ctypes.byref(f_u))) - self._check(self._lib.ENR_getUnits(self._handle, p, ctypes.byref(p_u))) - self._check(self._lib.ENR_getUnits(self._handle, q, ctypes.byref(q_u))) - return { 'flow': f_us[f_u.value], 'pressure': p_us[p_u.value], 'quality': q_us[q_u.value] } - - - def times(self) -> dict[str, int]: - ts = [] - for i in range(1, 5): - t = ctypes.c_int(1) - self._check(self._lib.ENR_getTimes(self._handle, ctypes.c_int(i), ctypes.byref(t))) - ts.append(t.value) - d = {} - category = ['report_start', 'report_step', 'sim_duration', 'num_periods'] - for i in range(4): - d[category[i]] = ts[i] - return d - - - def element_name(self) -> dict[str, list[str]]: - sizes = self.net_size() - - node_type = ctypes.c_int(1) - nodes = [] - for i in range(1, sizes['node'] + 1): - name = ctypes.c_char_p() - name_len = ctypes.c_int() - self._check(self._lib.ENR_getElementName(self._handle, node_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - nodes.append(name.value.decode()) - self._lib.ENR_free(ctypes.byref(name)) - - link_type = ctypes.c_int(2) - links = [] - for i in range(1, sizes['link'] + 1): - name = ctypes.c_char_p() - name_len = ctypes.c_int() - self._check(self._lib.ENR_getElementName(self._handle, link_type, ctypes.c_int(i), ctypes.byref(name), ctypes.byref(name_len))) - links.append(name.value.decode()) - self._lib.ENR_free(ctypes.byref(name)) - - return { 'nodes' : nodes, 'links': links } - - - def energy_usage(self) -> list[dict[str, Any]]: - size = self.net_size()['pump'] - usages = [] - category = ['utilization', 'avg.efficiency', 'avg.kW/flow', 'avg.kwatts', 'max.kwatts', 'cost/day' ] - links = self.element_name()['links'] - for i in range(1, size + 1): - index = ctypes.c_int() - values = ctypes.POINTER(ctypes.c_float)() - length = ctypes.c_int() - self._check(self._lib.ENR_getEnergyUsage(self._handle, ctypes.c_int(i), ctypes.byref(index), ctypes.byref(values), ctypes.byref(length))) - assert length.value == 6 - d = { 'pump' : links[index.value - 1] } - for j in range(length.value): - d |= { category[j] : values[j] } - usages.append(d) - self._lib.ENR_free(ctypes.byref(values)) - return usages - - - def reactions(self) -> dict[str, float]: - values = ctypes.POINTER(ctypes.c_float)() - length = ctypes.c_int() - self._check(self._lib.ENR_getNetReacts(self._handle, ctypes.byref(values), ctypes.byref(length))) - assert length.value == 4 - category = ['bulk', 'wall', 'tank', 'source'] - d = {} - for i in range(4): - d[category[i]] = values[i] - self._lib.ENR_free(ctypes.byref(values)) - return d - - - def node_results(self) -> list[dict[str, Any]]: - size = self.net_size()['node'] - num_periods = self.times()['num_periods'] - nodes = self.element_name()['nodes'] - category = ['demand', 'head', 'pressure', 'quality'] - ds = [] - for i in range(1, size + 1): - d = { 'node' : nodes[i - 1], 'result' : [] } - for j in range(num_periods): - values = ctypes.POINTER(ctypes.c_float)() - length = ctypes.c_int() - self._check(self._lib.ENR_getNodeResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - assert length.value == len(category) - attributes = {} - for k in range(length.value): - attributes[category[k]] = values[k] - d['result'].append(attributes) - self._lib.ENR_free(ctypes.byref(values)) - ds.append(d) - return ds - - - def link_results(self) -> list[dict[str, Any]]: - size = self.net_size()['link'] - num_periods = self.times()['num_periods'] - links = self.element_name()['links'] - category = ['flow', 'velocity', 'headloss', 'quality', 'status', 'setting', 'reaction', 'friction'] - ds = [] - - for i in range(1, size + 1): - d = { 'link' : links[i - 1], 'result' : [] } - for j in range(num_periods): - values = ctypes.POINTER(ctypes.c_float)() - length = ctypes.c_int() - self._check(self._lib.ENR_getLinkResult(self._handle, j, i, ctypes.byref(values), ctypes.byref(length))) - assert length.value == len(category) - attributes = {} - for k in range(length.value): - if category[k] == 'status': - if values[k] == 2.0: - attributes[category[k]] = 'CLOSED' - else: - attributes[category[k]] = 'OPEN' - continue - attributes[category[k]] = values[k] - d['result'].append(attributes) - self._lib.ENR_free(ctypes.byref(values)) - ds.append(d) - return ds - - - def dump(self) -> dict[str, Any]: - data = {} - data |= { 'version' : self.version() } - data |= { 'net_size' : self.net_size() } - data |= { 'units' : self.units() } - data |= { 'times' : self.times() } - data |= { 'element_name' : self.element_name() } - data |= { 'energy_usage' : self.energy_usage() } - data |= { 'reactions' : self.reactions() } - data |= { 'node_results' : self.node_results() } - data |= { 'link_results' : self.link_results() } - return data - - -def _dump_output(path: str) -> dict[str, Any]: - opt = Output(path) - data = opt.dump() - with open(path + '.json', 'w') as f: - json.dump(data, f) - return data - - -def dump_output(path: str) -> str: - data = _dump_output(path) - return json.dumps(data) - - -def dump_report(path: str) -> str: - return open(path, 'r').read() - - -def dump_output_binary(path: str) -> str: - with open(path, 'rb') as f: - data = f.read() - bast64_data = base64.b64encode(data) - return str(bast64_data, 'utf-8') - -#DingZQ, 2025-02-04, 返回dict[str, Any] -def run_project_return_dict(name: str, readable_output: bool = False) -> dict[str, Any]: - if not project.have_project(name): - raise Exception(f'Not found project [{name}]') - - dir = os.path.abspath(os.getcwd()) - - db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') - inp_out.dump_inp(name, db_inp, '2') - - input = name + '.db' - exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') - command = f'{exe} {inp} {rpt} {opt}' - - data = {} - - result = os.system(command) - if result != 0: - data['simulation_result'] = 'failed' - else: - data['simulation_result'] = 'successful' - if readable_output: - data ['output'] = _dump_output(opt) - else: - data['output'] = dump_output_binary(opt) - - data['report'] = dump_report(rpt) - - return data - -# original code -def run_project(name: str, readable_output: bool = False) -> str: - if not project.have_project(name): - raise Exception(f'Not found project [{name}]') - - dir = os.path.abspath(os.getcwd()) - - db_inp = os.path.join(os.path.join(dir, 'db_inp'), name + '.db.inp') - inp_out.dump_inp(name, db_inp, '2') - - input = name + '.db' - exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - inp = os.path.join(os.path.join(dir, 'db_inp'), input + '.inp') - rpt = os.path.join(os.path.join(dir, 'temp'), input + '.rpt') - opt = os.path.join(os.path.join(dir, 'temp'), input + '.opt') - - command = f'{exe} {inp} {rpt} {opt}' - logging.info(f"Run simulation at {datetime.now()}") - logging.info(command) - - data = {} - - # DingZQ, 2025-06-02, 使用subprocess.Popen捕获输出到全局日志, 原来的代码是这么写的 - result = os.system(command) - #logging.info(f"Simulation result: {result}") - - if result != 0: - data['simulation_result'] = 'failed' - - logging.error('simulation failed') - - else: - data['simulation_result'] = 'successful' - logging.info('simulation successful') - - if readable_output: - data |= _dump_output(opt) - else: - data['output'] = dump_output_binary(opt) - - data['report'] = dump_report(rpt) - #logging.info(f"Report: {data['report']}") - - return json.dumps(data) - - -def run_inp(name: str) -> str: - dir = os.path.abspath(os.getcwd()) - - exe = os.path.join(os.path.join(dir, 'epanet'), 'runepanet.exe') - inp = os.path.join(os.path.join(dir, 'inp'), name + '.inp') - rpt = os.path.join(os.path.join(dir, 'temp'), name + '.rpt') - opt = os.path.join(os.path.join(dir, 'temp'), name + '.opt') - command = f'{exe} {inp} {rpt} {opt}' - - data = {} - - result = os.system(command) - if result != 0: - data['simulation_result'] = 'failed' - else: - data['simulation_result'] = 'successful' - # data |= _dump_output(opt) - data['output'] = dump_output_binary(opt) - - data['report'] = dump_report(rpt) - - return json.dumps(data) diff --git a/epanet/epanet2-0.dll b/epanet/epanet2-0.dll deleted file mode 100644 index 129d2eb..0000000 Binary files a/epanet/epanet2-0.dll and /dev/null differ diff --git a/epanet/epanet2-2.2.0.dll b/epanet/epanet2-2.2.0.dll deleted file mode 100644 index a3bea5e..0000000 Binary files a/epanet/epanet2-2.2.0.dll and /dev/null differ diff --git a/epanet/epanet2-2.3.0.dll b/epanet/epanet2-2.3.0.dll deleted file mode 100644 index 2a3cab1..0000000 Binary files a/epanet/epanet2-2.3.0.dll and /dev/null differ diff --git a/epanet/epanet2-cannot run.dll b/epanet/epanet2-cannot run.dll deleted file mode 100644 index cdebe8f..0000000 Binary files a/epanet/epanet2-cannot run.dll and /dev/null differ diff --git a/epanet/epanet2_ec.c b/epanet/epanet2_ec.c deleted file mode 100644 index cf6fd8f..0000000 --- a/epanet/epanet2_ec.c +++ /dev/null @@ -1,6027 +0,0 @@ -/* Generated by Cython 3.1.0 */ - -/* BEGIN: Cython Metadata -{ - "distutils": { - "name": "epanet.epanet2_ec", - "sources": [ - "epanet\\epanet2_ec.py" - ] - }, - "module_name": "epanet.epanet2_ec" -} -END: Cython Metadata */ - -#ifndef PY_SSIZE_T_CLEAN -#define PY_SSIZE_T_CLEAN -#endif /* PY_SSIZE_T_CLEAN */ -/* InitLimitedAPI */ -#if defined(Py_LIMITED_API) && !defined(CYTHON_LIMITED_API) - #define CYTHON_LIMITED_API 1 -#endif - -#include "Python.h" -#ifndef Py_PYTHON_H - #error Python headers needed to compile C extensions, please install development version of Python. -#elif PY_VERSION_HEX < 0x03080000 - #error Cython requires Python 3.8+. -#else -#define __PYX_ABI_VERSION "3_1_0" -#define CYTHON_HEX_VERSION 0x030100F0 -#define CYTHON_FUTURE_DIVISION 1 -/* CModulePreamble */ -#include -#ifndef offsetof - #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) -#endif -#if !defined(_WIN32) && !defined(WIN32) && !defined(MS_WINDOWS) - #ifndef __stdcall - #define __stdcall - #endif - #ifndef __cdecl - #define __cdecl - #endif - #ifndef __fastcall - #define __fastcall - #endif -#endif -#ifndef DL_IMPORT - #define DL_IMPORT(t) t -#endif -#ifndef DL_EXPORT - #define DL_EXPORT(t) t -#endif -#define __PYX_COMMA , -#ifndef HAVE_LONG_LONG - #define HAVE_LONG_LONG -#endif -#ifndef PY_LONG_LONG - #define PY_LONG_LONG LONG_LONG -#endif -#ifndef Py_HUGE_VAL - #define Py_HUGE_VAL HUGE_VAL -#endif -#define __PYX_LIMITED_VERSION_HEX PY_VERSION_HEX -#if defined(GRAALVM_PYTHON) - /* For very preliminary testing purposes. Most variables are set the same as PyPy. - The existence of this section does not imply that anything works or is even tested */ - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 1 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 0 - #undef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #undef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 1 - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #undef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 0 - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #undef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #undef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #undef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 1 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#elif defined(PYPY_VERSION) - #define CYTHON_COMPILING_IN_PYPY 1 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 0 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #ifndef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #endif - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #undef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 1 - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #ifndef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 1 - #endif - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 0 - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #if PY_VERSION_HEX < 0x03090000 - #undef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 0 - #elif !defined(CYTHON_PEP489_MULTI_PHASE_INIT) - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #undef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE (PYPY_VERSION_NUM >= 0x07030C00) - #endif - #undef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 0 - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC (PYPY_VERSION_NUM >= 0x07031100) - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#elif defined(CYTHON_LIMITED_API) - #ifdef Py_LIMITED_API - #undef __PYX_LIMITED_VERSION_HEX - #define __PYX_LIMITED_VERSION_HEX Py_LIMITED_API - #endif - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 0 - #define CYTHON_COMPILING_IN_LIMITED_API 1 - #define CYTHON_COMPILING_IN_GRAAL 0 - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #undef CYTHON_CLINE_IN_TRACEBACK - #define CYTHON_CLINE_IN_TRACEBACK 0 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 0 - #undef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 1 - #undef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 0 - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #undef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 0 - #ifndef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #endif - #undef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 0 - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #ifndef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 - #endif - #undef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 0 - #undef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 0 - #undef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 0 - #undef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 0 - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #undef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) - #undef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 0 - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #ifndef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #endif - #undef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING 0 - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 0 - #endif - #ifndef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND (__PYX_LIMITED_VERSION_HEX >= 0x030A0000) - #endif - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #undef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 0 - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 0 - #endif - #undef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS 0 -#else - #define CYTHON_COMPILING_IN_PYPY 0 - #define CYTHON_COMPILING_IN_CPYTHON 1 - #define CYTHON_COMPILING_IN_LIMITED_API 0 - #define CYTHON_COMPILING_IN_GRAAL 0 - #ifdef Py_GIL_DISABLED - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 1 - #else - #define CYTHON_COMPILING_IN_CPYTHON_FREETHREADING 0 - #endif - #if PY_VERSION_HEX < 0x030A0000 - #undef CYTHON_USE_TYPE_SLOTS - #define CYTHON_USE_TYPE_SLOTS 1 - #elif !defined(CYTHON_USE_TYPE_SLOTS) - #define CYTHON_USE_TYPE_SLOTS 1 - #endif - #ifndef CYTHON_USE_TYPE_SPECS - #define CYTHON_USE_TYPE_SPECS 0 - #endif - #ifndef CYTHON_USE_PYTYPE_LOOKUP - #define CYTHON_USE_PYTYPE_LOOKUP 1 - #endif - #ifndef CYTHON_USE_PYLONG_INTERNALS - #define CYTHON_USE_PYLONG_INTERNALS 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_USE_PYLIST_INTERNALS - #define CYTHON_USE_PYLIST_INTERNALS 0 - #elif !defined(CYTHON_USE_PYLIST_INTERNALS) - #define CYTHON_USE_PYLIST_INTERNALS 1 - #endif - #ifndef CYTHON_USE_UNICODE_INTERNALS - #define CYTHON_USE_UNICODE_INTERNALS 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING || PY_VERSION_HEX >= 0x030B00A2 - #undef CYTHON_USE_UNICODE_WRITER - #define CYTHON_USE_UNICODE_WRITER 0 - #elif !defined(CYTHON_USE_UNICODE_WRITER) - #define CYTHON_USE_UNICODE_WRITER 1 - #endif - #ifndef CYTHON_AVOID_BORROWED_REFS - #define CYTHON_AVOID_BORROWED_REFS 0 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 1 - #elif !defined(CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS) - #define CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS 0 - #endif - #ifndef CYTHON_ASSUME_SAFE_MACROS - #define CYTHON_ASSUME_SAFE_MACROS 1 - #endif - #ifndef CYTHON_ASSUME_SAFE_SIZE - #define CYTHON_ASSUME_SAFE_SIZE 1 - #endif - #ifndef CYTHON_UNPACK_METHODS - #define CYTHON_UNPACK_METHODS 1 - #endif - #ifndef CYTHON_FAST_THREAD_STATE - #define CYTHON_FAST_THREAD_STATE 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_FAST_GIL - #define CYTHON_FAST_GIL 0 - #elif !defined(CYTHON_FAST_GIL) - #define CYTHON_FAST_GIL (PY_VERSION_HEX < 0x030C00A6) - #endif - #ifndef CYTHON_METH_FASTCALL - #define CYTHON_METH_FASTCALL 1 - #endif - #ifndef CYTHON_FAST_PYCALL - #define CYTHON_FAST_PYCALL 1 - #endif - #ifndef CYTHON_PEP487_INIT_SUBCLASS - #define CYTHON_PEP487_INIT_SUBCLASS 1 - #endif - #ifndef CYTHON_PEP489_MULTI_PHASE_INIT - #define CYTHON_PEP489_MULTI_PHASE_INIT 1 - #endif - #ifndef CYTHON_USE_MODULE_STATE - #define CYTHON_USE_MODULE_STATE 0 - #endif - #ifndef CYTHON_USE_SYS_MONITORING - #define CYTHON_USE_SYS_MONITORING (PY_VERSION_HEX >= 0x030d00B1) - #endif - #ifndef CYTHON_USE_TP_FINALIZE - #define CYTHON_USE_TP_FINALIZE 1 - #endif - #ifndef CYTHON_USE_AM_SEND - #define CYTHON_USE_AM_SEND 1 - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - #undef CYTHON_USE_DICT_VERSIONS - #define CYTHON_USE_DICT_VERSIONS 0 - #elif !defined(CYTHON_USE_DICT_VERSIONS) - #define CYTHON_USE_DICT_VERSIONS (PY_VERSION_HEX < 0x030C00A5 && !CYTHON_USE_MODULE_STATE) - #endif - #ifndef CYTHON_USE_EXC_INFO_STACK - #define CYTHON_USE_EXC_INFO_STACK 1 - #endif - #ifndef CYTHON_UPDATE_DESCRIPTOR_DOC - #define CYTHON_UPDATE_DESCRIPTOR_DOC 1 - #endif - #ifndef CYTHON_USE_FREELISTS - #define CYTHON_USE_FREELISTS (!CYTHON_COMPILING_IN_CPYTHON_FREETHREADING) - #endif -#endif -#ifndef CYTHON_FAST_PYCCALL -#define CYTHON_FAST_PYCCALL CYTHON_FAST_PYCALL -#endif -#ifndef CYTHON_VECTORCALL -#if CYTHON_COMPILING_IN_LIMITED_API -#define CYTHON_VECTORCALL (__PYX_LIMITED_VERSION_HEX >= 0x030C0000) -#else -#define CYTHON_VECTORCALL (CYTHON_FAST_PYCCALL && PY_VERSION_HEX >= 0x030800B1) -#endif -#endif -#define CYTHON_BACKPORT_VECTORCALL (CYTHON_METH_FASTCALL && PY_VERSION_HEX < 0x030800B1) -#if CYTHON_USE_PYLONG_INTERNALS - #undef SHIFT - #undef BASE - #undef MASK - #ifdef SIZEOF_VOID_P - enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) }; - #endif -#endif -#ifndef __has_attribute - #define __has_attribute(x) 0 -#endif -#ifndef __has_cpp_attribute - #define __has_cpp_attribute(x) 0 -#endif -#ifndef CYTHON_RESTRICT - #if defined(__GNUC__) - #define CYTHON_RESTRICT __restrict__ - #elif defined(_MSC_VER) && _MSC_VER >= 1400 - #define CYTHON_RESTRICT __restrict - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_RESTRICT restrict - #else - #define CYTHON_RESTRICT - #endif -#endif -#ifndef CYTHON_UNUSED - #if defined(__cplusplus) - /* for clang __has_cpp_attribute(maybe_unused) is true even before C++17 - * but leads to warnings with -pedantic, since it is a C++17 feature */ - #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) - #if __has_cpp_attribute(maybe_unused) - #define CYTHON_UNUSED [[maybe_unused]] - #endif - #endif - #endif -#endif -#ifndef CYTHON_UNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) -# define CYTHON_UNUSED __attribute__ ((__unused__)) -# else -# define CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_UNUSED_VAR -# if defined(__cplusplus) - template void CYTHON_UNUSED_VAR( const T& ) { } -# else -# define CYTHON_UNUSED_VAR(x) (void)(x) -# endif -#endif -#ifndef CYTHON_MAYBE_UNUSED_VAR - #define CYTHON_MAYBE_UNUSED_VAR(x) CYTHON_UNUSED_VAR(x) -#endif -#ifndef CYTHON_NCP_UNUSED -# if CYTHON_COMPILING_IN_CPYTHON -# define CYTHON_NCP_UNUSED -# else -# define CYTHON_NCP_UNUSED CYTHON_UNUSED -# endif -#endif -#ifndef CYTHON_USE_CPP_STD_MOVE - #if defined(__cplusplus) && (\ - __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1600)) - #define CYTHON_USE_CPP_STD_MOVE 1 - #else - #define CYTHON_USE_CPP_STD_MOVE 0 - #endif -#endif -#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) -#ifdef _MSC_VER - #ifndef _MSC_STDINT_H_ - #if _MSC_VER < 1300 - typedef unsigned char uint8_t; - typedef unsigned short uint16_t; - typedef unsigned int uint32_t; - #else - typedef unsigned __int8 uint8_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int32 uint32_t; - #endif - #endif - #if _MSC_VER < 1300 - #ifdef _WIN64 - typedef unsigned long long __pyx_uintptr_t; - #else - typedef unsigned int __pyx_uintptr_t; - #endif - #else - #ifdef _WIN64 - typedef unsigned __int64 __pyx_uintptr_t; - #else - typedef unsigned __int32 __pyx_uintptr_t; - #endif - #endif -#else - #include - typedef uintptr_t __pyx_uintptr_t; -#endif -#ifndef CYTHON_FALLTHROUGH - #if defined(__cplusplus) - /* for clang __has_cpp_attribute(fallthrough) is true even before C++17 - * but leads to warnings with -pedantic, since it is a C++17 feature */ - #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) - #if __has_cpp_attribute(fallthrough) - #define CYTHON_FALLTHROUGH [[fallthrough]] - #endif - #endif - #ifndef CYTHON_FALLTHROUGH - #if __has_cpp_attribute(clang::fallthrough) - #define CYTHON_FALLTHROUGH [[clang::fallthrough]] - #elif __has_cpp_attribute(gnu::fallthrough) - #define CYTHON_FALLTHROUGH [[gnu::fallthrough]] - #endif - #endif - #endif - #ifndef CYTHON_FALLTHROUGH - #if __has_attribute(fallthrough) - #define CYTHON_FALLTHROUGH __attribute__((fallthrough)) - #else - #define CYTHON_FALLTHROUGH - #endif - #endif - #if defined(__clang__) && defined(__apple_build_version__) - #if __apple_build_version__ < 7000000 - #undef CYTHON_FALLTHROUGH - #define CYTHON_FALLTHROUGH - #endif - #endif -#endif -#ifndef Py_UNREACHABLE - #define Py_UNREACHABLE() assert(0); abort() -#endif -#ifdef __cplusplus - template - struct __PYX_IS_UNSIGNED_IMPL {static const bool value = T(0) < T(-1);}; - #define __PYX_IS_UNSIGNED(type) (__PYX_IS_UNSIGNED_IMPL::value) -#else - #define __PYX_IS_UNSIGNED(type) (((type)-1) > 0) -#endif -#if CYTHON_COMPILING_IN_PYPY == 1 - #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x030A0000) -#else - #define __PYX_NEED_TP_PRINT_SLOT (PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000) -#endif -#define __PYX_REINTERPRET_FUNCION(func_pointer, other_pointer) ((func_pointer)(void(*)(void))(other_pointer)) - -/* CInitCode */ -#ifndef CYTHON_INLINE - #if defined(__clang__) - #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) - #elif defined(__GNUC__) - #define CYTHON_INLINE __inline__ - #elif defined(_MSC_VER) - #define CYTHON_INLINE __inline - #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define CYTHON_INLINE inline - #else - #define CYTHON_INLINE - #endif -#endif - -/* PythonCompatibility */ -#define __PYX_BUILD_PY_SSIZE_T "n" -#define CYTHON_FORMAT_SSIZE_T "z" -#define __Pyx_BUILTIN_MODULE_NAME "builtins" -#define __Pyx_DefaultClassType PyType_Type -#if CYTHON_COMPILING_IN_LIMITED_API - #ifndef CO_OPTIMIZED - static int CO_OPTIMIZED; - #endif - #ifndef CO_NEWLOCALS - static int CO_NEWLOCALS; - #endif - #ifndef CO_VARARGS - static int CO_VARARGS; - #endif - #ifndef CO_VARKEYWORDS - static int CO_VARKEYWORDS; - #endif - #ifndef CO_ASYNC_GENERATOR - static int CO_ASYNC_GENERATOR; - #endif - #ifndef CO_GENERATOR - static int CO_GENERATOR; - #endif - #ifndef CO_COROUTINE - static int CO_COROUTINE; - #endif -#else - #ifndef CO_COROUTINE - #define CO_COROUTINE 0x80 - #endif - #ifndef CO_ASYNC_GENERATOR - #define CO_ASYNC_GENERATOR 0x200 - #endif -#endif -static int __Pyx_init_co_variables(void); -#if PY_VERSION_HEX >= 0x030900A4 || defined(Py_IS_TYPE) - #define __Pyx_IS_TYPE(ob, type) Py_IS_TYPE(ob, type) -#else - #define __Pyx_IS_TYPE(ob, type) (((const PyObject*)ob)->ob_type == (type)) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_Is) - #define __Pyx_Py_Is(x, y) Py_Is(x, y) -#else - #define __Pyx_Py_Is(x, y) ((x) == (y)) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsNone) - #define __Pyx_Py_IsNone(ob) Py_IsNone(ob) -#else - #define __Pyx_Py_IsNone(ob) __Pyx_Py_Is((ob), Py_None) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsTrue) - #define __Pyx_Py_IsTrue(ob) Py_IsTrue(ob) -#else - #define __Pyx_Py_IsTrue(ob) __Pyx_Py_Is((ob), Py_True) -#endif -#if PY_VERSION_HEX >= 0x030A00B1 || defined(Py_IsFalse) - #define __Pyx_Py_IsFalse(ob) Py_IsFalse(ob) -#else - #define __Pyx_Py_IsFalse(ob) __Pyx_Py_Is((ob), Py_False) -#endif -#define __Pyx_NoneAsNull(obj) (__Pyx_Py_IsNone(obj) ? NULL : (obj)) -#if PY_VERSION_HEX >= 0x030900F0 && !CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyObject_GC_IsFinalized(o) PyObject_GC_IsFinalized(o) -#else - #define __Pyx_PyObject_GC_IsFinalized(o) _PyGC_FINALIZED(o) -#endif -#ifndef Py_TPFLAGS_CHECKTYPES - #define Py_TPFLAGS_CHECKTYPES 0 -#endif -#ifndef Py_TPFLAGS_HAVE_INDEX - #define Py_TPFLAGS_HAVE_INDEX 0 -#endif -#ifndef Py_TPFLAGS_HAVE_NEWBUFFER - #define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#endif -#ifndef Py_TPFLAGS_HAVE_FINALIZE - #define Py_TPFLAGS_HAVE_FINALIZE 0 -#endif -#ifndef Py_TPFLAGS_SEQUENCE - #define Py_TPFLAGS_SEQUENCE 0 -#endif -#ifndef Py_TPFLAGS_MAPPING - #define Py_TPFLAGS_MAPPING 0 -#endif -#ifndef METH_STACKLESS - #define METH_STACKLESS 0 -#endif -#ifndef METH_FASTCALL - #ifndef METH_FASTCALL - #define METH_FASTCALL 0x80 - #endif - typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject *const *args, Py_ssize_t nargs); - typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject *const *args, - Py_ssize_t nargs, PyObject *kwnames); -#else - #if PY_VERSION_HEX >= 0x030d00A4 - # define __Pyx_PyCFunctionFast PyCFunctionFast - # define __Pyx_PyCFunctionFastWithKeywords PyCFunctionFastWithKeywords - #else - # define __Pyx_PyCFunctionFast _PyCFunctionFast - # define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords - #endif -#endif -#if CYTHON_METH_FASTCALL - #define __Pyx_METH_FASTCALL METH_FASTCALL - #define __Pyx_PyCFunction_FastCall __Pyx_PyCFunctionFast - #define __Pyx_PyCFunction_FastCallWithKeywords __Pyx_PyCFunctionFastWithKeywords -#else - #define __Pyx_METH_FASTCALL METH_VARARGS - #define __Pyx_PyCFunction_FastCall PyCFunction - #define __Pyx_PyCFunction_FastCallWithKeywords PyCFunctionWithKeywords -#endif -#if CYTHON_VECTORCALL - #define __pyx_vectorcallfunc vectorcallfunc - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET PY_VECTORCALL_ARGUMENTS_OFFSET - #define __Pyx_PyVectorcall_NARGS(n) PyVectorcall_NARGS((size_t)(n)) -#elif CYTHON_BACKPORT_VECTORCALL - typedef PyObject *(*__pyx_vectorcallfunc)(PyObject *callable, PyObject *const *args, - size_t nargsf, PyObject *kwnames); - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) - #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(((size_t)(n)) & ~__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET)) -#else - #define __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET 0 - #define __Pyx_PyVectorcall_NARGS(n) ((Py_ssize_t)(n)) -#endif -#if PY_VERSION_HEX >= 0x030900B1 -#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_CheckExact(func) -#else -#define __Pyx_PyCFunction_CheckExact(func) PyCFunction_Check(func) -#endif -#define __Pyx_CyOrPyCFunction_Check(func) PyCFunction_Check(func) -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) (((PyCFunctionObject*)(func))->m_ml->ml_meth) -#elif !CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_CyOrPyCFunction_GET_FUNCTION(func) PyCFunction_GET_FUNCTION(func) -#endif -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_CyOrPyCFunction_GET_FLAGS(func) (((PyCFunctionObject*)(func))->m_ml->ml_flags) -static CYTHON_INLINE PyObject* __Pyx_CyOrPyCFunction_GET_SELF(PyObject *func) { - return (__Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_STATIC) ? NULL : ((PyCFunctionObject*)func)->m_self; -} -#endif -static CYTHON_INLINE int __Pyx__IsSameCFunction(PyObject *func, void (*cfunc)(void)) { -#if CYTHON_COMPILING_IN_LIMITED_API - return PyCFunction_Check(func) && PyCFunction_GetFunction(func) == (PyCFunction) cfunc; -#else - return PyCFunction_Check(func) && PyCFunction_GET_FUNCTION(func) == (PyCFunction) cfunc; -#endif -} -#define __Pyx_IsSameCFunction(func, cfunc) __Pyx__IsSameCFunction(func, cfunc) -#if __PYX_LIMITED_VERSION_HEX < 0x03090000 - #define __Pyx_PyType_FromModuleAndSpec(m, s, b) ((void)m, PyType_FromSpecWithBases(s, b)) - typedef PyObject *(*__Pyx_PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); -#else - #define __Pyx_PyType_FromModuleAndSpec(m, s, b) PyType_FromModuleAndSpec(m, s, b) - #define __Pyx_PyCMethod PyCMethod -#endif -#ifndef METH_METHOD - #define METH_METHOD 0x200 -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) - #define PyObject_Malloc(s) PyMem_Malloc(s) - #define PyObject_Free(p) PyMem_Free(p) - #define PyObject_Realloc(p) PyMem_Realloc(p) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) -#elif CYTHON_COMPILING_IN_GRAAL - #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) _PyFrame_SetLineNumber((frame), (lineno)) -#else - #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) - #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyThreadState_Current PyThreadState_Get() -#elif !CYTHON_FAST_THREAD_STATE - #define __Pyx_PyThreadState_Current PyThreadState_GET() -#elif PY_VERSION_HEX >= 0x030d00A1 - #define __Pyx_PyThreadState_Current PyThreadState_GetUnchecked() -#else - #define __Pyx_PyThreadState_Current _PyThreadState_UncheckedGet() -#endif -#if CYTHON_USE_MODULE_STATE -static CYTHON_INLINE void *__Pyx__PyModule_GetState(PyObject *op) -{ - void *result; - result = PyModule_GetState(op); - if (!result) - Py_FatalError("Couldn't find the module state"); - return result; -} -#define __Pyx_PyModule_GetState(o) (__pyx_mstatetype *)__Pyx__PyModule_GetState(o) -#else -#define __Pyx_PyModule_GetState(op) ((void)op,__pyx_mstate_global) -#endif -#define __Pyx_PyObject_GetSlot(obj, name, func_ctype) __Pyx_PyType_GetSlot(Py_TYPE((PyObject *) obj), name, func_ctype) -#define __Pyx_PyObject_TryGetSlot(obj, name, func_ctype) __Pyx_PyType_TryGetSlot(Py_TYPE(obj), name, func_ctype) -#define __Pyx_PyObject_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(Py_TYPE(obj), sub, name, func_ctype) -#define __Pyx_PyObject_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSubSlot(Py_TYPE(obj), sub, name, func_ctype) -#if CYTHON_USE_TYPE_SLOTS - #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((type)->name) - #define __Pyx_PyType_TryGetSlot(type, name, func_ctype) __Pyx_PyType_GetSlot(type, name, func_ctype) - #define __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) (((type)->sub) ? ((type)->sub->name) : NULL) - #define __Pyx_PyType_TryGetSubSlot(type, sub, name, func_ctype) __Pyx_PyType_GetSubSlot(type, sub, name, func_ctype) -#else - #define __Pyx_PyType_GetSlot(type, name, func_ctype) ((func_ctype) PyType_GetSlot((type), Py_##name)) - #define __Pyx_PyType_TryGetSlot(type, name, func_ctype)\ - ((__PYX_LIMITED_VERSION_HEX >= 0x030A0000 ||\ - (PyType_GetFlags(type) & Py_TPFLAGS_HEAPTYPE) || __Pyx_get_runtime_version() >= 0x030A0000) ?\ - __Pyx_PyType_GetSlot(type, name, func_ctype) : NULL) - #define __Pyx_PyType_GetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_GetSlot(obj, name, func_ctype) - #define __Pyx_PyType_TryGetSubSlot(obj, sub, name, func_ctype) __Pyx_PyType_TryGetSlot(obj, name, func_ctype) -#endif -#if CYTHON_COMPILING_IN_CPYTHON || defined(_PyDict_NewPresized) -#define __Pyx_PyDict_NewPresized(n) ((n <= 8) ? PyDict_New() : _PyDict_NewPresized(n)) -#else -#define __Pyx_PyDict_NewPresized(n) PyDict_New() -#endif -#define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) -#define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) -#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_UNICODE_INTERNALS -#define __Pyx_PyDict_GetItemStrWithError(dict, name) _PyDict_GetItem_KnownHash(dict, name, ((PyASCIIObject *) name)->hash) -static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStr(PyObject *dict, PyObject *name) { - PyObject *res = __Pyx_PyDict_GetItemStrWithError(dict, name); - if (res == NULL) PyErr_Clear(); - return res; -} -#elif !CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07020000 -#define __Pyx_PyDict_GetItemStrWithError PyDict_GetItemWithError -#define __Pyx_PyDict_GetItemStr PyDict_GetItem -#else -static CYTHON_INLINE PyObject * __Pyx_PyDict_GetItemStrWithError(PyObject *dict, PyObject *name) { -#if CYTHON_COMPILING_IN_PYPY - return PyDict_GetItem(dict, name); -#else - PyDictEntry *ep; - PyDictObject *mp = (PyDictObject*) dict; - long hash = ((PyStringObject *) name)->ob_shash; - assert(hash != -1); - ep = (mp->ma_lookup)(mp, name, hash); - if (ep == NULL) { - return NULL; - } - return ep->me_value; -#endif -} -#define __Pyx_PyDict_GetItemStr PyDict_GetItem -#endif -#if CYTHON_USE_TYPE_SLOTS - #define __Pyx_PyType_GetFlags(tp) (((PyTypeObject *)tp)->tp_flags) - #define __Pyx_PyType_HasFeature(type, feature) ((__Pyx_PyType_GetFlags(type) & (feature)) != 0) -#else - #define __Pyx_PyType_GetFlags(tp) (PyType_GetFlags((PyTypeObject *)tp)) - #define __Pyx_PyType_HasFeature(type, feature) PyType_HasFeature(type, feature) -#endif -#define __Pyx_PyObject_GetIterNextFunc(iterator) __Pyx_PyObject_GetSlot(iterator, tp_iternext, iternextfunc) -#if CYTHON_USE_TYPE_SPECS && PY_VERSION_HEX >= 0x03080000 -#define __Pyx_PyHeapTypeObject_GC_Del(obj) {\ - PyTypeObject *type = Py_TYPE((PyObject*)obj);\ - assert(__Pyx_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE));\ - PyObject_GC_Del(obj);\ - Py_DECREF(type);\ -} -#else -#define __Pyx_PyHeapTypeObject_GC_Del(obj) PyObject_GC_Del(obj) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API - #define __Pyx_PyUnicode_READY(op) (0) - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((void)u, 1114111U) - #define __Pyx_PyUnicode_KIND(u) ((void)u, (0)) - #define __Pyx_PyUnicode_DATA(u) ((void*)u) - #define __Pyx_PyUnicode_READ(k, d, i) ((void)k, PyUnicode_ReadChar((PyObject*)(d), i)) - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GetLength(u)) -#else - #if PY_VERSION_HEX >= 0x030C0000 - #define __Pyx_PyUnicode_READY(op) (0) - #else - #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ - 0 : _PyUnicode_Ready((PyObject *)(op))) - #endif - #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) - #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) - #define __Pyx_PyUnicode_KIND(u) ((int)PyUnicode_KIND(u)) - #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) - #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) - #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, (Py_UCS4) ch) - #if PY_VERSION_HEX >= 0x030C0000 - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_LENGTH(u)) - #else - #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x03090000 - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : ((PyCompactUnicodeObject *)(u))->wstr_length)) - #else - #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) - #endif - #endif -#endif -#if CYTHON_COMPILING_IN_PYPY - #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) -#else - #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) - #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ - PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) -#endif -#if CYTHON_COMPILING_IN_PYPY - #if !defined(PyUnicode_DecodeUnicodeEscape) - #define PyUnicode_DecodeUnicodeEscape(s, size, errors) PyUnicode_Decode(s, size, "unicode_escape", errors) - #endif - #if !defined(PyUnicode_Contains) - #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) - #endif - #if !defined(PyByteArray_Check) - #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) - #endif - #if !defined(PyObject_Format) - #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) - #endif -#endif -#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None || (PyUnicode_Check(b) && !PyUnicode_CheckExact(b)))) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) -#if CYTHON_COMPILING_IN_CPYTHON - #define __Pyx_PySequence_ListKeepNew(obj)\ - (likely(PyList_CheckExact(obj) && Py_REFCNT(obj) == 1) ? __Pyx_NewRef(obj) : PySequence_List(obj)) -#else - #define __Pyx_PySequence_ListKeepNew(obj) PySequence_List(obj) -#endif -#ifndef PySet_CheckExact - #define PySet_CheckExact(obj) __Pyx_IS_TYPE(obj, &PySet_Type) -#endif -#if PY_VERSION_HEX >= 0x030900A4 - #define __Pyx_SET_REFCNT(obj, refcnt) Py_SET_REFCNT(obj, refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SET_SIZE(obj, size) -#else - #define __Pyx_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt) - #define __Pyx_SET_SIZE(obj, size) Py_SIZE(obj) = (size) -#endif -#if CYTHON_COMPILING_IN_LIMITED_API || CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS || !CYTHON_ASSUME_SAFE_MACROS - #if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - #define __Pyx_PyList_GetItemRef(o, i) PyList_GetItemRef(o, i) - #else - #define __Pyx_PyList_GetItemRef(o, i) PySequence_GetItem(o, i) - #endif -#else - #define __Pyx_PyList_GetItemRef(o, i) __Pyx_NewRef(PyList_GET_ITEM(o, i)) -#endif -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 -#define __Pyx_PyDict_GetItemRef(dict, key, result) PyDict_GetItemRef(dict, key, result) -#elif CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS -static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { - *result = PyObject_GetItem(dict, key); - if (*result == NULL) { - if (PyErr_ExceptionMatches(PyExc_KeyError)) { - PyErr_Clear(); - return 0; - } - return -1; - } - return 1; -} -#else -static CYTHON_INLINE int __Pyx_PyDict_GetItemRef(PyObject *dict, PyObject *key, PyObject **result) { - *result = PyDict_GetItemWithError(dict, key); - if (*result == NULL) { - return PyErr_Occurred() ? -1 : 0; - } - Py_INCREF(*result); - return 1; -} -#endif -#if defined(CYTHON_DEBUG_VISIT_CONST) && CYTHON_DEBUG_VISIT_CONST - #define __Pyx_VISIT_CONST(obj) Py_VISIT(obj) -#else - #define __Pyx_VISIT_CONST(obj) -#endif -#if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PySequence_ITEM(o, i) PySequence_ITEM(o, i) - #define __Pyx_PySequence_SIZE(seq) Py_SIZE(seq) - #define __Pyx_PyTuple_SET_ITEM(o, i, v) (PyTuple_SET_ITEM(o, i, v), (0)) - #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GET_ITEM(o, i) - #define __Pyx_PyList_SET_ITEM(o, i, v) (PyList_SET_ITEM(o, i, v), (0)) - #define __Pyx_PyList_GET_ITEM(o, i) PyList_GET_ITEM(o, i) -#else - #define __Pyx_PySequence_ITEM(o, i) PySequence_GetItem(o, i) - #define __Pyx_PySequence_SIZE(seq) PySequence_Size(seq) - #define __Pyx_PyTuple_SET_ITEM(o, i, v) PyTuple_SetItem(o, i, v) - #define __Pyx_PyTuple_GET_ITEM(o, i) PyTuple_GetItem(o, i) - #define __Pyx_PyList_SET_ITEM(o, i, v) PyList_SetItem(o, i, v) - #define __Pyx_PyList_GET_ITEM(o, i) PyList_GetItem(o, i) -#endif -#if CYTHON_ASSUME_SAFE_SIZE - #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_GET_SIZE(o) - #define __Pyx_PyList_GET_SIZE(o) PyList_GET_SIZE(o) - #define __Pyx_PySet_GET_SIZE(o) PySet_GET_SIZE(o) - #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_GET_SIZE(o) - #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_GET_SIZE(o) - #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GET_LENGTH(o) -#else - #define __Pyx_PyTuple_GET_SIZE(o) PyTuple_Size(o) - #define __Pyx_PyList_GET_SIZE(o) PyList_Size(o) - #define __Pyx_PySet_GET_SIZE(o) PySet_Size(o) - #define __Pyx_PyBytes_GET_SIZE(o) PyBytes_Size(o) - #define __Pyx_PyByteArray_GET_SIZE(o) PyByteArray_Size(o) - #define __Pyx_PyUnicode_GET_LENGTH(o) PyUnicode_GetLength(o) -#endif -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - #define __Pyx_PyImport_AddModuleRef(name) PyImport_AddModuleRef(name) -#else - static CYTHON_INLINE PyObject *__Pyx_PyImport_AddModuleRef(const char *name) { - PyObject *module = PyImport_AddModule(name); - Py_XINCREF(module); - return module; - } -#endif -#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_InternFromString) - #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) -#endif -#define __Pyx_PyLong_FromHash_t PyLong_FromSsize_t -#define __Pyx_PyLong_AsHash_t __Pyx_PyIndex_AsSsize_t -#if __PYX_LIMITED_VERSION_HEX >= 0x030A0000 - #define __Pyx_PySendResult PySendResult -#else - typedef enum { - PYGEN_RETURN = 0, - PYGEN_ERROR = -1, - PYGEN_NEXT = 1, - } __Pyx_PySendResult; -#endif -#if CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX < 0x030A00A3 - typedef __Pyx_PySendResult (*__Pyx_pyiter_sendfunc)(PyObject *iter, PyObject *value, PyObject **result); -#else - #define __Pyx_pyiter_sendfunc sendfunc -#endif -#if !CYTHON_USE_AM_SEND -#define __PYX_HAS_PY_AM_SEND 0 -#elif __PYX_LIMITED_VERSION_HEX >= 0x030A0000 -#define __PYX_HAS_PY_AM_SEND 1 -#else -#define __PYX_HAS_PY_AM_SEND 2 // our own backported implementation -#endif -#if __PYX_HAS_PY_AM_SEND < 2 - #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods -#else - typedef struct { - unaryfunc am_await; - unaryfunc am_aiter; - unaryfunc am_anext; - __Pyx_pyiter_sendfunc am_send; - } __Pyx_PyAsyncMethodsStruct; - #define __Pyx_SlotTpAsAsync(s) ((PyAsyncMethods*)(s)) -#endif -#if CYTHON_USE_AM_SEND && PY_VERSION_HEX < 0x030A00F0 - #define __Pyx_TPFLAGS_HAVE_AM_SEND (1UL << 21) -#else - #define __Pyx_TPFLAGS_HAVE_AM_SEND (0) -#endif -#if PY_VERSION_HEX >= 0x03090000 -#define __Pyx_PyInterpreterState_Get() PyInterpreterState_Get() -#else -#define __Pyx_PyInterpreterState_Get() PyThreadState_Get()->interp -#endif -#if CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030A0000 -#ifdef __cplusplus -extern "C" -#endif -PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize); -#endif -#if CYTHON_COMPILING_IN_LIMITED_API -static int __Pyx_init_co_variable(PyObject *inspect, const char* name, int *write_to) { - int value; - PyObject *py_value = PyObject_GetAttrString(inspect, name); - if (!py_value) return 0; - value = (int) PyLong_AsLong(py_value); - Py_DECREF(py_value); - *write_to = value; - return value != -1 || !PyErr_Occurred(); -} -static int __Pyx_init_co_variables(void) { - PyObject *inspect; - int result; - inspect = PyImport_ImportModule("inspect"); - result = -#if !defined(CO_OPTIMIZED) - __Pyx_init_co_variable(inspect, "CO_OPTIMIZED", &CO_OPTIMIZED) && -#endif -#if !defined(CO_NEWLOCALS) - __Pyx_init_co_variable(inspect, "CO_NEWLOCALS", &CO_NEWLOCALS) && -#endif -#if !defined(CO_VARARGS) - __Pyx_init_co_variable(inspect, "CO_VARARGS", &CO_VARARGS) && -#endif -#if !defined(CO_VARKEYWORDS) - __Pyx_init_co_variable(inspect, "CO_VARKEYWORDS", &CO_VARKEYWORDS) && -#endif -#if !defined(CO_ASYNC_GENERATOR) - __Pyx_init_co_variable(inspect, "CO_ASYNC_GENERATOR", &CO_ASYNC_GENERATOR) && -#endif -#if !defined(CO_GENERATOR) - __Pyx_init_co_variable(inspect, "CO_GENERATOR", &CO_GENERATOR) && -#endif -#if !defined(CO_COROUTINE) - __Pyx_init_co_variable(inspect, "CO_COROUTINE", &CO_COROUTINE) && -#endif - 1; - Py_DECREF(inspect); - return result ? 0 : -1; -} -#else -static int __Pyx_init_co_variables(void) { - return 0; // It's a limited API-only feature -} -#endif - -/* MathInitCode */ -#if defined(_WIN32) || defined(WIN32) || defined(MS_WINDOWS) - #ifndef _USE_MATH_DEFINES - #define _USE_MATH_DEFINES - #endif -#endif -#include -#ifdef NAN -#define __PYX_NAN() ((float) NAN) -#else -static CYTHON_INLINE float __PYX_NAN() { - float value; - memset(&value, 0xFF, sizeof(value)); - return value; -} -#endif -#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) -#define __Pyx_truncl trunc -#else -#define __Pyx_truncl truncl -#endif - -#ifndef CYTHON_CLINE_IN_TRACEBACK_RUNTIME -#define CYTHON_CLINE_IN_TRACEBACK_RUNTIME 0 -#endif -#ifndef CYTHON_CLINE_IN_TRACEBACK -#define CYTHON_CLINE_IN_TRACEBACK CYTHON_CLINE_IN_TRACEBACK_RUNTIME -#endif -#if CYTHON_CLINE_IN_TRACEBACK -#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; __pyx_clineno = __LINE__; (void) __pyx_clineno; } -#else -#define __PYX_MARK_ERR_POS(f_index, lineno) { __pyx_filename = __pyx_f[f_index]; (void) __pyx_filename; __pyx_lineno = lineno; (void) __pyx_lineno; (void) __pyx_clineno; } -#endif -#define __PYX_ERR(f_index, lineno, Ln_error) \ - { __PYX_MARK_ERR_POS(f_index, lineno) goto Ln_error; } - -#ifdef CYTHON_EXTERN_C - #undef __PYX_EXTERN_C - #define __PYX_EXTERN_C CYTHON_EXTERN_C -#elif defined(__PYX_EXTERN_C) - #ifdef _MSC_VER - #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") - #else - #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. - #endif -#else - #ifdef __cplusplus - #define __PYX_EXTERN_C extern "C" - #else - #define __PYX_EXTERN_C extern - #endif -#endif - -#define __PYX_HAVE__epanet__epanet2_ec -#define __PYX_HAVE_API__epanet__epanet2_ec -/* Early includes */ -#ifdef _OPENMP -#include -#endif /* _OPENMP */ - -#if defined(PYREX_WITHOUT_ASSERTIONS) && !defined(CYTHON_WITHOUT_ASSERTIONS) -#define CYTHON_WITHOUT_ASSERTIONS -#endif - -#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 -#define __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 0 -#define __PYX_DEFAULT_STRING_ENCODING "" -#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString -#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize -#define __Pyx_uchar_cast(c) ((unsigned char)c) -#define __Pyx_long_cast(x) ((long)x) -#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ - (sizeof(type) < sizeof(Py_ssize_t)) ||\ - (sizeof(type) > sizeof(Py_ssize_t) &&\ - likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX) &&\ - (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ - v == (type)PY_SSIZE_T_MIN))) ||\ - (sizeof(type) == sizeof(Py_ssize_t) &&\ - (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ - v == (type)PY_SSIZE_T_MAX))) ) -static CYTHON_INLINE int __Pyx_is_valid_index(Py_ssize_t i, Py_ssize_t limit) { - return (size_t) i < (size_t) limit; -} -#if defined (__cplusplus) && __cplusplus >= 201103L - #include - #define __Pyx_sst_abs(value) std::abs(value) -#elif SIZEOF_INT >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) abs(value) -#elif SIZEOF_LONG >= SIZEOF_SIZE_T - #define __Pyx_sst_abs(value) labs(value) -#elif defined (_MSC_VER) - #define __Pyx_sst_abs(value) ((Py_ssize_t)_abs64(value)) -#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #define __Pyx_sst_abs(value) llabs(value) -#elif defined (__GNUC__) - #define __Pyx_sst_abs(value) __builtin_llabs(value) -#else - #define __Pyx_sst_abs(value) ((value<0) ? -value : value) -#endif -static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s); -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*); -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); -static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char*); -#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) -#define __Pyx_PyBytes_FromString PyBytes_FromString -#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); -#if CYTHON_ASSUME_SAFE_MACROS - #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AS_STRING(s)) - #define __Pyx_PyByteArray_AsString(s) PyByteArray_AS_STRING(s) -#else - #define __Pyx_PyBytes_AsWritableString(s) ((char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsWritableSString(s) ((signed char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsWritableUString(s) ((unsigned char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsString(s) ((const char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsSString(s) ((const signed char*) PyBytes_AsString(s)) - #define __Pyx_PyBytes_AsUString(s) ((const unsigned char*) PyBytes_AsString(s)) - #define __Pyx_PyByteArray_AsString(s) PyByteArray_AsString(s) -#endif -#define __Pyx_PyObject_AsWritableString(s) ((char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableSString(s) ((signed char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*)(__pyx_uintptr_t) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s)) -#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) -#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) -#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) -#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) -#define __Pyx_PyUnicode_FromOrdinal(o) PyUnicode_FromOrdinal((int)o) -#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode -static CYTHON_INLINE PyObject *__Pyx_NewRef(PyObject *obj) { -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_NewRef) - return Py_NewRef(obj); -#else - Py_INCREF(obj); - return obj; -#endif -} -static CYTHON_INLINE PyObject *__Pyx_XNewRef(PyObject *obj) { -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030a0000 || defined(Py_XNewRef) - return Py_XNewRef(obj); -#else - Py_XINCREF(obj); - return obj; -#endif -} -static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b); -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b); -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject*); -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x); -#define __Pyx_PySequence_Tuple(obj)\ - (likely(PyTuple_CheckExact(obj)) ? __Pyx_NewRef(obj) : PySequence_Tuple(obj)) -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); -static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t); -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject*); -#if CYTHON_ASSUME_SAFE_MACROS -#define __Pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) -#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AS_DOUBLE(x) -#else -#define __Pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) -#define __Pyx_PyFloat_AS_DOUBLE(x) PyFloat_AsDouble(x) -#endif -#define __Pyx_PyFloat_AsFloat(x) ((float) __Pyx_PyFloat_AsDouble(x)) -#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) -#if CYTHON_USE_PYLONG_INTERNALS - #if PY_VERSION_HEX >= 0x030C00A7 - #ifndef _PyLong_SIGN_MASK - #define _PyLong_SIGN_MASK 3 - #endif - #ifndef _PyLong_NON_SIZE_BITS - #define _PyLong_NON_SIZE_BITS 3 - #endif - #define __Pyx_PyLong_Sign(x) (((PyLongObject*)x)->long_value.lv_tag & _PyLong_SIGN_MASK) - #define __Pyx_PyLong_IsNeg(x) ((__Pyx_PyLong_Sign(x) & 2) != 0) - #define __Pyx_PyLong_IsNonNeg(x) (!__Pyx_PyLong_IsNeg(x)) - #define __Pyx_PyLong_IsZero(x) (__Pyx_PyLong_Sign(x) & 1) - #define __Pyx_PyLong_IsPos(x) (__Pyx_PyLong_Sign(x) == 0) - #define __Pyx_PyLong_CompactValueUnsigned(x) (__Pyx_PyLong_Digits(x)[0]) - #define __Pyx_PyLong_DigitCount(x) ((Py_ssize_t) (((PyLongObject*)x)->long_value.lv_tag >> _PyLong_NON_SIZE_BITS)) - #define __Pyx_PyLong_SignedDigitCount(x)\ - ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * __Pyx_PyLong_DigitCount(x)) - #if defined(PyUnstable_Long_IsCompact) && defined(PyUnstable_Long_CompactValue) - #define __Pyx_PyLong_IsCompact(x) PyUnstable_Long_IsCompact((PyLongObject*) x) - #define __Pyx_PyLong_CompactValue(x) PyUnstable_Long_CompactValue((PyLongObject*) x) - #else - #define __Pyx_PyLong_IsCompact(x) (((PyLongObject*)x)->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS)) - #define __Pyx_PyLong_CompactValue(x) ((1 - (Py_ssize_t) __Pyx_PyLong_Sign(x)) * (Py_ssize_t) __Pyx_PyLong_Digits(x)[0]) - #endif - typedef Py_ssize_t __Pyx_compact_pylong; - typedef size_t __Pyx_compact_upylong; - #else - #define __Pyx_PyLong_IsNeg(x) (Py_SIZE(x) < 0) - #define __Pyx_PyLong_IsNonNeg(x) (Py_SIZE(x) >= 0) - #define __Pyx_PyLong_IsZero(x) (Py_SIZE(x) == 0) - #define __Pyx_PyLong_IsPos(x) (Py_SIZE(x) > 0) - #define __Pyx_PyLong_CompactValueUnsigned(x) ((Py_SIZE(x) == 0) ? 0 : __Pyx_PyLong_Digits(x)[0]) - #define __Pyx_PyLong_DigitCount(x) __Pyx_sst_abs(Py_SIZE(x)) - #define __Pyx_PyLong_SignedDigitCount(x) Py_SIZE(x) - #define __Pyx_PyLong_IsCompact(x) (Py_SIZE(x) == 0 || Py_SIZE(x) == 1 || Py_SIZE(x) == -1) - #define __Pyx_PyLong_CompactValue(x)\ - ((Py_SIZE(x) == 0) ? (sdigit) 0 : ((Py_SIZE(x) < 0) ? -(sdigit)__Pyx_PyLong_Digits(x)[0] : (sdigit)__Pyx_PyLong_Digits(x)[0])) - typedef sdigit __Pyx_compact_pylong; - typedef digit __Pyx_compact_upylong; - #endif - #if PY_VERSION_HEX >= 0x030C00A5 - #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->long_value.ob_digit) - #else - #define __Pyx_PyLong_Digits(x) (((PyLongObject*)x)->ob_digit) - #endif -#endif -#if __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) -#elif __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeASCII(c_str, size, NULL) -#else - #define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) -#endif - - -/* Test for GCC > 2.95 */ -#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) - #define likely(x) __builtin_expect(!!(x), 1) - #define unlikely(x) __builtin_expect(!!(x), 0) -#else /* !__GNUC__ or GCC < 2.95 */ - #define likely(x) (x) - #define unlikely(x) (x) -#endif /* __GNUC__ */ -/* PretendToInitialize */ -#ifdef __cplusplus -#include -template -static void __Pyx_pretend_to_initialize(T* ptr) { -#if __cplusplus > 201103L - if ((std::is_trivially_default_constructible::value)) -#endif - *ptr = T(); - (void)ptr; -} -#else -static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; } -#endif - - -#if !CYTHON_USE_MODULE_STATE -static PyObject *__pyx_m = NULL; -#endif -static int __pyx_lineno; -static int __pyx_clineno = 0; -static const char * const __pyx_cfilenm = __FILE__; -static const char *__pyx_filename; - -/* #### Code section: filename_table ### */ - -static const char* const __pyx_f[] = { - "epanet/epanet2_ec.py", -}; -/* #### Code section: utility_code_proto_before_types ### */ -/* CriticalSections.proto */ -#if !CYTHON_COMPILING_IN_CPYTHON_FREETHREADING -#define __Pyx_PyCriticalSection void* -#define __Pyx_PyCriticalSection2 void* -#define __Pyx_PyCriticalSection_Begin1(cs, arg) (void)cs -#define __Pyx_PyCriticalSection_Begin2(cs, arg1, arg2) (void)cs -#define __Pyx_PyCriticalSection_End1(cs) -#define __Pyx_PyCriticalSection_End2(cs) -#else -#define __Pyx_PyCriticalSection PyCriticalSection -#define __Pyx_PyCriticalSection2 PyCriticalSection2 -#define __Pyx_PyCriticalSection_Begin1 PyCriticalSection_Begin -#define __Pyx_PyCriticalSection_Begin2 PyCriticalSection2_Begin -#define __Pyx_PyCriticalSection_End1 PyCriticalSection_End -#define __Pyx_PyCriticalSection_End2 PyCriticalSection2_End -#endif -#if PY_VERSION_HEX < 0x030d0000 || CYTHON_COMPILING_IN_LIMITED_API -#define __Pyx_BEGIN_CRITICAL_SECTION(o) { -#define __Pyx_END_CRITICAL_SECTION() } -#else -#define __Pyx_BEGIN_CRITICAL_SECTION Py_BEGIN_CRITICAL_SECTION -#define __Pyx_END_CRITICAL_SECTION Py_END_CRITICAL_SECTION -#endif - -/* Atomics.proto */ -#include -#ifndef CYTHON_ATOMICS - #define CYTHON_ATOMICS 1 -#endif -#define __PYX_CYTHON_ATOMICS_ENABLED() CYTHON_ATOMICS -#define __PYX_GET_CYTHON_COMPILING_IN_CPYTHON_FREETHREADING() CYTHON_COMPILING_IN_CPYTHON_FREETHREADING -#define __pyx_atomic_int_type int -#define __pyx_nonatomic_int_type int -#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ - (__STDC_VERSION__ >= 201112L) &&\ - !defined(__STDC_NO_ATOMICS__)) - #include -#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ - (__cplusplus >= 201103L) ||\ - (defined(_MSC_VER) && _MSC_VER >= 1700))) - #include -#endif -#if CYTHON_ATOMICS && (defined(__STDC_VERSION__) &&\ - (__STDC_VERSION__ >= 201112L) &&\ - !defined(__STDC_NO_ATOMICS__) &&\ - ATOMIC_INT_LOCK_FREE == 2) - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type atomic_int - #define __pyx_atomic_ptr_type atomic_uintptr_t - #define __pyx_nonatomic_ptr_type uintptr_t - #define __pyx_atomic_incr_relaxed(value) atomic_fetch_add_explicit(value, 1, memory_order_relaxed) - #define __pyx_atomic_incr_acq_rel(value) atomic_fetch_add_explicit(value, 1, memory_order_acq_rel) - #define __pyx_atomic_decr_acq_rel(value) atomic_fetch_sub_explicit(value, 1, memory_order_acq_rel) - #define __pyx_atomic_sub(value, arg) atomic_fetch_sub(value, arg) - #define __pyx_atomic_int_cmp_exchange(value, expected, desired) atomic_compare_exchange_strong(value, expected, desired) - #define __pyx_atomic_load(value) atomic_load(value) - #define __pyx_atomic_store(value, new_value) atomic_store(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) atomic_load_explicit(value, memory_order_relaxed) - #define __pyx_atomic_pointer_load_acquire(value) atomic_load_explicit(value, memory_order_acquire) - #define __pyx_atomic_pointer_exchange(value, new_value) atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) - #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) - #pragma message ("Using standard C atomics") - #elif defined(__PYX_DEBUG_ATOMICS) - #warning "Using standard C atomics" - #endif -#elif CYTHON_ATOMICS && (defined(__cplusplus) && (\ - (__cplusplus >= 201103L) ||\ -\ - (defined(_MSC_VER) && _MSC_VER >= 1700)) &&\ - ATOMIC_INT_LOCK_FREE == 2) - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type std::atomic_int - #define __pyx_atomic_ptr_type std::atomic_uintptr_t - #define __pyx_nonatomic_ptr_type uintptr_t - #define __pyx_atomic_incr_relaxed(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_relaxed) - #define __pyx_atomic_incr_acq_rel(value) std::atomic_fetch_add_explicit(value, 1, std::memory_order_acq_rel) - #define __pyx_atomic_decr_acq_rel(value) std::atomic_fetch_sub_explicit(value, 1, std::memory_order_acq_rel) - #define __pyx_atomic_sub(value, arg) std::atomic_fetch_sub(value, arg) - #define __pyx_atomic_int_cmp_exchange(value, expected, desired) std::atomic_compare_exchange_strong(value, expected, desired) - #define __pyx_atomic_load(value) std::atomic_load(value) - #define __pyx_atomic_store(value, new_value) std::atomic_store(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) std::atomic_load_explicit(value, std::memory_order_relaxed) - #define __pyx_atomic_pointer_load_acquire(value) std::atomic_load_explicit(value, std::memory_order_acquire) - #define __pyx_atomic_pointer_exchange(value, new_value) std::atomic_exchange(value, (__pyx_nonatomic_ptr_type)new_value) - #if defined(__PYX_DEBUG_ATOMICS) && defined(_MSC_VER) - #pragma message ("Using standard C++ atomics") - #elif defined(__PYX_DEBUG_ATOMICS) - #warning "Using standard C++ atomics" - #endif -#elif CYTHON_ATOMICS && (__GNUC__ >= 5 || (__GNUC__ == 4 &&\ - (__GNUC_MINOR__ > 1 ||\ - (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 2)))) - #define __pyx_atomic_ptr_type void* - #define __pyx_atomic_incr_relaxed(value) __sync_fetch_and_add(value, 1) - #define __pyx_atomic_incr_acq_rel(value) __sync_fetch_and_add(value, 1) - #define __pyx_atomic_decr_acq_rel(value) __sync_fetch_and_sub(value, 1) - #define __pyx_atomic_sub(value, arg) __sync_fetch_and_sub(value, arg) - static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { - __pyx_nonatomic_int_type old = __sync_val_compare_and_swap(value, *expected, desired); - int result = old == *expected; - *expected = old; - return result; - } - #define __pyx_atomic_load(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_store(value, new_value) __sync_lock_test_and_set(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_pointer_load_acquire(value) __sync_fetch_and_add(value, 0) - #define __pyx_atomic_pointer_exchange(value, new_value) __sync_lock_test_and_set(value, (__pyx_atomic_ptr_type)new_value) - #ifdef __PYX_DEBUG_ATOMICS - #warning "Using GNU atomics" - #endif -#elif CYTHON_ATOMICS && defined(_MSC_VER) - #include - #undef __pyx_atomic_int_type - #define __pyx_atomic_int_type long - #define __pyx_atomic_ptr_type void* - #undef __pyx_nonatomic_int_type - #define __pyx_nonatomic_int_type long - #pragma intrinsic (_InterlockedExchangeAdd, _InterlockedExchange, _InterlockedCompareExchange, _InterlockedCompareExchangePointer, _InterlockedExchangePointer) - #define __pyx_atomic_incr_relaxed(value) _InterlockedExchangeAdd(value, 1) - #define __pyx_atomic_incr_acq_rel(value) _InterlockedExchangeAdd(value, 1) - #define __pyx_atomic_decr_acq_rel(value) _InterlockedExchangeAdd(value, -1) - #define __pyx_atomic_sub(value, arg) _InterlockedExchangeAdd(value, -arg) - static CYTHON_INLINE int __pyx_atomic_int_cmp_exchange(__pyx_atomic_int_type* value, __pyx_nonatomic_int_type* expected, __pyx_nonatomic_int_type desired) { - __pyx_nonatomic_int_type old = _InterlockedCompareExchange(value, desired, *expected); - int result = old == *expected; - *expected = old; - return result; - } - #define __pyx_atomic_load(value) _InterlockedExchangeAdd(value, 0) - #define __pyx_atomic_store(value, new_value) _InterlockedExchange(value, new_value) - #define __pyx_atomic_pointer_load_relaxed(value) *(void * volatile *)value - #define __pyx_atomic_pointer_load_acquire(value) _InterlockedCompareExchangePointer(value, 0, 0) - #define __pyx_atomic_pointer_exchange(value, new_value) _InterlockedExchangePointer(value, (__pyx_atomic_ptr_type)new_value) - #ifdef __PYX_DEBUG_ATOMICS - #pragma message ("Using MSVC atomics") - #endif -#else - #undef CYTHON_ATOMICS - #define CYTHON_ATOMICS 0 - #ifdef __PYX_DEBUG_ATOMICS - #warning "Not using atomics" - #endif -#endif -#if CYTHON_ATOMICS - #define __pyx_add_acquisition_count(memview)\ - __pyx_atomic_incr_relaxed(__pyx_get_slice_count_pointer(memview)) - #define __pyx_sub_acquisition_count(memview)\ - __pyx_atomic_decr_acq_rel(__pyx_get_slice_count_pointer(memview)) -#else - #define __pyx_add_acquisition_count(memview)\ - __pyx_add_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) - #define __pyx_sub_acquisition_count(memview)\ - __pyx_sub_acquisition_count_locked(__pyx_get_slice_count_pointer(memview), memview->lock) -#endif - -/* #### Code section: numeric_typedefs ### */ -/* #### Code section: complex_type_declarations ### */ -/* #### Code section: type_declarations ### */ - -/*--- Type declarations ---*/ -/* #### Code section: utility_code_proto ### */ - -/* --- Runtime support code (head) --- */ -/* Refnanny.proto */ -#ifndef CYTHON_REFNANNY - #define CYTHON_REFNANNY 0 -#endif -#if CYTHON_REFNANNY - typedef struct { - void (*INCREF)(void*, PyObject*, Py_ssize_t); - void (*DECREF)(void*, PyObject*, Py_ssize_t); - void (*GOTREF)(void*, PyObject*, Py_ssize_t); - void (*GIVEREF)(void*, PyObject*, Py_ssize_t); - void* (*SetupContext)(const char*, Py_ssize_t, const char*); - void (*FinishContext)(void**); - } __Pyx_RefNannyAPIStruct; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); - #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; - #define __Pyx_RefNannySetupContext(name, acquire_gil)\ - if (acquire_gil) {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ - PyGILState_Release(__pyx_gilstate_save);\ - } else {\ - __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), (__LINE__), (__FILE__));\ - } - #define __Pyx_RefNannyFinishContextNogil() {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __Pyx_RefNannyFinishContext();\ - PyGILState_Release(__pyx_gilstate_save);\ - } - #define __Pyx_RefNannyFinishContextNogil() {\ - PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ - __Pyx_RefNannyFinishContext();\ - PyGILState_Release(__pyx_gilstate_save);\ - } - #define __Pyx_RefNannyFinishContext()\ - __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), (__LINE__)) - #define __Pyx_XINCREF(r) do { if((r) == NULL); else {__Pyx_INCREF(r); }} while(0) - #define __Pyx_XDECREF(r) do { if((r) == NULL); else {__Pyx_DECREF(r); }} while(0) - #define __Pyx_XGOTREF(r) do { if((r) == NULL); else {__Pyx_GOTREF(r); }} while(0) - #define __Pyx_XGIVEREF(r) do { if((r) == NULL); else {__Pyx_GIVEREF(r);}} while(0) -#else - #define __Pyx_RefNannyDeclarations - #define __Pyx_RefNannySetupContext(name, acquire_gil) - #define __Pyx_RefNannyFinishContextNogil() - #define __Pyx_RefNannyFinishContext() - #define __Pyx_INCREF(r) Py_INCREF(r) - #define __Pyx_DECREF(r) Py_DECREF(r) - #define __Pyx_GOTREF(r) - #define __Pyx_GIVEREF(r) - #define __Pyx_XINCREF(r) Py_XINCREF(r) - #define __Pyx_XDECREF(r) Py_XDECREF(r) - #define __Pyx_XGOTREF(r) - #define __Pyx_XGIVEREF(r) -#endif -#define __Pyx_Py_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; Py_XDECREF(tmp);\ - } while (0) -#define __Pyx_XDECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_XDECREF(tmp);\ - } while (0) -#define __Pyx_DECREF_SET(r, v) do {\ - PyObject *tmp = (PyObject *) r;\ - r = v; __Pyx_DECREF(tmp);\ - } while (0) -#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) -#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) - -/* PyErrExceptionMatches.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_ExceptionMatches(err) __Pyx_PyErr_ExceptionMatchesInState(__pyx_tstate, err) -static CYTHON_INLINE int __Pyx_PyErr_ExceptionMatchesInState(PyThreadState* tstate, PyObject* err); -#else -#define __Pyx_PyErr_ExceptionMatches(err) PyErr_ExceptionMatches(err) -#endif - -/* PyThreadStateGet.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyThreadState_declare PyThreadState *__pyx_tstate; -#define __Pyx_PyThreadState_assign __pyx_tstate = __Pyx_PyThreadState_Current; -#if PY_VERSION_HEX >= 0x030C00A6 -#define __Pyx_PyErr_Occurred() (__pyx_tstate->current_exception != NULL) -#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->current_exception ? (PyObject*) Py_TYPE(__pyx_tstate->current_exception) : (PyObject*) NULL) -#else -#define __Pyx_PyErr_Occurred() (__pyx_tstate->curexc_type != NULL) -#define __Pyx_PyErr_CurrentExceptionType() (__pyx_tstate->curexc_type) -#endif -#else -#define __Pyx_PyThreadState_declare -#define __Pyx_PyThreadState_assign -#define __Pyx_PyErr_Occurred() (PyErr_Occurred() != NULL) -#define __Pyx_PyErr_CurrentExceptionType() PyErr_Occurred() -#endif - -/* PyErrFetchRestore.proto */ -#if CYTHON_FAST_THREAD_STATE -#define __Pyx_PyErr_Clear() __Pyx_ErrRestore(NULL, NULL, NULL) -#define __Pyx_ErrRestoreWithState(type, value, tb) __Pyx_ErrRestoreInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) __Pyx_ErrFetchInState(PyThreadState_GET(), type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) __Pyx_ErrRestoreInState(__pyx_tstate, type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) __Pyx_ErrFetchInState(__pyx_tstate, type, value, tb) -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb); -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb); -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A6 -#define __Pyx_PyErr_SetNone(exc) (Py_INCREF(exc), __Pyx_ErrRestore((exc), NULL, NULL)) -#else -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#endif -#else -#define __Pyx_PyErr_Clear() PyErr_Clear() -#define __Pyx_PyErr_SetNone(exc) PyErr_SetNone(exc) -#define __Pyx_ErrRestoreWithState(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchWithState(type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestoreInState(tstate, type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetchInState(tstate, type, value, tb) PyErr_Fetch(type, value, tb) -#define __Pyx_ErrRestore(type, value, tb) PyErr_Restore(type, value, tb) -#define __Pyx_ErrFetch(type, value, tb) PyErr_Fetch(type, value, tb) -#endif - -/* PyObjectGetAttrStr.proto */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name); -#else -#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) -#endif - -/* PyObjectGetAttrStrNoError.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name); - -/* GetBuiltinName.proto */ -static PyObject *__Pyx_GetBuiltinName(PyObject *name); - -/* PyDictVersioning.proto */ -#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS -#define __PYX_DICT_VERSION_INIT ((PY_UINT64_T) -1) -#define __PYX_GET_DICT_VERSION(dict) (((PyDictObject*)(dict))->ma_version_tag) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var)\ - (version_var) = __PYX_GET_DICT_VERSION(dict);\ - (cache_var) = (value); -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) {\ - static PY_UINT64_T __pyx_dict_version = 0;\ - static PyObject *__pyx_dict_cached_value = NULL;\ - if (likely(__PYX_GET_DICT_VERSION(DICT) == __pyx_dict_version)) {\ - (VAR) = __pyx_dict_cached_value;\ - } else {\ - (VAR) = __pyx_dict_cached_value = (LOOKUP);\ - __pyx_dict_version = __PYX_GET_DICT_VERSION(DICT);\ - }\ -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj); -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj); -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version); -#else -#define __PYX_GET_DICT_VERSION(dict) (0) -#define __PYX_UPDATE_DICT_CACHE(dict, value, cache_var, version_var) -#define __PYX_PY_DICT_LOOKUP_IF_MODIFIED(VAR, DICT, LOOKUP) (VAR) = (LOOKUP); -#endif - -/* GetModuleGlobalName.proto */ -#if CYTHON_USE_DICT_VERSIONS -#define __Pyx_GetModuleGlobalName(var, name) do {\ - static PY_UINT64_T __pyx_dict_version = 0;\ - static PyObject *__pyx_dict_cached_value = NULL;\ - (var) = (likely(__pyx_dict_version == __PYX_GET_DICT_VERSION(__pyx_mstate_global->__pyx_d))) ?\ - (likely(__pyx_dict_cached_value) ? __Pyx_NewRef(__pyx_dict_cached_value) : __Pyx_GetBuiltinName(name)) :\ - __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ -} while(0) -#define __Pyx_GetModuleGlobalNameUncached(var, name) do {\ - PY_UINT64_T __pyx_dict_version;\ - PyObject *__pyx_dict_cached_value;\ - (var) = __Pyx__GetModuleGlobalName(name, &__pyx_dict_version, &__pyx_dict_cached_value);\ -} while(0) -static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value); -#else -#define __Pyx_GetModuleGlobalName(var, name) (var) = __Pyx__GetModuleGlobalName(name) -#define __Pyx_GetModuleGlobalNameUncached(var, name) (var) = __Pyx__GetModuleGlobalName(name) -static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name); -#endif - -/* CLineInTraceback.proto */ -#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME -static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line); -#else -#define __Pyx_CLineForTraceback(tstate, c_line) (((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0) -#endif - -/* CodeObjectCache.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API -typedef PyObject __Pyx_CachedCodeObjectType; -#else -typedef PyCodeObject __Pyx_CachedCodeObjectType; -#endif -typedef struct { - __Pyx_CachedCodeObjectType* code_object; - int code_line; -} __Pyx_CodeObjectCacheEntry; -struct __Pyx_CodeObjectCache { - int count; - int max_count; - __Pyx_CodeObjectCacheEntry* entries; - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_int_type accessor_count; - #endif -}; -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); -static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line); -static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object); - -/* AddTraceback.proto */ -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename); - -/* FormatTypeName.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API -typedef PyObject *__Pyx_TypeName; -#define __Pyx_FMT_TYPENAME "%U" -#define __Pyx_DECREF_TypeName(obj) Py_XDECREF(obj) -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 -#define __Pyx_PyType_GetFullyQualifiedName PyType_GetFullyQualifiedName -#else -static __Pyx_TypeName __Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp); -#endif -#else // !LIMITED_API -typedef const char *__Pyx_TypeName; -#define __Pyx_FMT_TYPENAME "%.200s" -#define __Pyx_PyType_GetFullyQualifiedName(tp) ((tp)->tp_name) -#define __Pyx_DECREF_TypeName(obj) -#endif - -/* GCCDiagnostics.proto */ -#if !defined(__INTEL_COMPILER) && defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) -#define __Pyx_HAS_GCC_DIAGNOSTIC -#endif - -/* PyFunctionFastCall.proto */ -#if CYTHON_FAST_PYCALL -#if !CYTHON_VECTORCALL -#define __Pyx_PyFunction_FastCall(func, args, nargs)\ - __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs); -#endif -#define __Pyx_BUILD_ASSERT_EXPR(cond)\ - (sizeof(char [1 - 2*!(cond)]) - 1) -#ifndef Py_MEMBER_SIZE -#define Py_MEMBER_SIZE(type, member) sizeof(((type *)0)->member) -#endif -#if !CYTHON_VECTORCALL -#if PY_VERSION_HEX >= 0x03080000 - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets() - #define __Pyx_PyFrame_GetLocalsplus(frame) ((frame)->f_localsplus) -#else - static size_t __pyx_pyframe_localsplus_offset = 0; - #include "frameobject.h" - #define __Pxy_PyFrame_Initialize_Offsets()\ - ((void)__Pyx_BUILD_ASSERT_EXPR(sizeof(PyFrameObject) == offsetof(PyFrameObject, f_localsplus) + Py_MEMBER_SIZE(PyFrameObject, f_localsplus)),\ - (void)(__pyx_pyframe_localsplus_offset = ((size_t)PyFrame_Type.tp_basicsize) - Py_MEMBER_SIZE(PyFrameObject, f_localsplus))) - #define __Pyx_PyFrame_GetLocalsplus(frame)\ - (assert(__pyx_pyframe_localsplus_offset), (PyObject **)(((char *)(frame)) + __pyx_pyframe_localsplus_offset)) -#endif -#endif -#endif - -/* PyObjectCall.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); -#else -#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) -#endif - -/* PyObjectCallMethO.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg); -#endif - -/* PyObjectFastCall.proto */ -#define __Pyx_PyObject_FastCall(func, args, nargs) __Pyx_PyObject_FastCallDict(func, args, (size_t)(nargs), NULL) -static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs); - -/* PyObjectVectorCallKwBuilder.proto */ -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); -#if CYTHON_VECTORCALL -#if PY_VERSION_HEX >= 0x03090000 -#define __Pyx_Object_Vectorcall_CallFromBuilder PyObject_Vectorcall -#else -#define __Pyx_Object_Vectorcall_CallFromBuilder _PyObject_Vectorcall -#endif -#define __Pyx_MakeVectorcallBuilderKwds(n) PyTuple_New(n) -static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n); -static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n); -#else -#define __Pyx_Object_Vectorcall_CallFromBuilder __Pyx_PyObject_FastCallDict -#define __Pyx_MakeVectorcallBuilderKwds(n) __Pyx_PyDict_NewPresized(n) -#define __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n) PyDict_SetItem(builder, key, value) -#define __Pyx_VectorcallBuilder_AddArgStr(key, value, builder, args, n) PyDict_SetItemString(builder, key, value) -#endif - -/* CIntToPy.proto */ -static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value); - -/* CIntFromPy.proto */ -static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *); - -/* CIntFromPy.proto */ -static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *); - -/* FastTypeChecks.proto */ -#if CYTHON_COMPILING_IN_CPYTHON -#define __Pyx_TypeCheck(obj, type) __Pyx_IsSubtype(Py_TYPE(obj), (PyTypeObject *)type) -#define __Pyx_TypeCheck2(obj, type1, type2) __Pyx_IsAnySubtype2(Py_TYPE(obj), (PyTypeObject *)type1, (PyTypeObject *)type2) -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b); -static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches(PyObject *err, PyObject *type); -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2); -#else -#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) -#define __Pyx_TypeCheck2(obj, type1, type2) (PyObject_TypeCheck(obj, (PyTypeObject *)type1) || PyObject_TypeCheck(obj, (PyTypeObject *)type2)) -#define __Pyx_PyErr_GivenExceptionMatches(err, type) PyErr_GivenExceptionMatches(err, type) -static CYTHON_INLINE int __Pyx_PyErr_GivenExceptionMatches2(PyObject *err, PyObject *type1, PyObject *type2) { - return PyErr_GivenExceptionMatches(err, type1) || PyErr_GivenExceptionMatches(err, type2); -} -#endif -#define __Pyx_PyErr_ExceptionMatches2(err1, err2) __Pyx_PyErr_GivenExceptionMatches2(__Pyx_PyErr_CurrentExceptionType(), err1, err2) -#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) -#ifdef PyExceptionInstance_Check - #define __Pyx_PyBaseException_Check(obj) PyExceptionInstance_Check(obj) -#else - #define __Pyx_PyBaseException_Check(obj) __Pyx_TypeCheck(obj, PyExc_BaseException) -#endif - -/* GetRuntimeVersion.proto */ -static unsigned long __Pyx_get_runtime_version(void); - -/* CheckBinaryVersion.proto */ -static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer); - -/* MultiPhaseInitModuleState.proto */ -#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE -static PyObject *__Pyx_State_FindModule(void*); -static int __Pyx_State_AddModule(PyObject* module, void*); -static int __Pyx_State_RemoveModule(void*); -#elif CYTHON_USE_MODULE_STATE -#define __Pyx_State_FindModule PyState_FindModule -#define __Pyx_State_AddModule PyState_AddModule -#define __Pyx_State_RemoveModule PyState_RemoveModule -#endif - -/* #### Code section: module_declarations ### */ -/* CythonABIVersion.proto */ -#if CYTHON_COMPILING_IN_LIMITED_API - #if CYTHON_METH_FASTCALL - #define __PYX_FASTCALL_ABI_SUFFIX "_fastcall" - #else - #define __PYX_FASTCALL_ABI_SUFFIX - #endif - #define __PYX_LIMITED_ABI_SUFFIX "limited" __PYX_FASTCALL_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX -#else - #define __PYX_LIMITED_ABI_SUFFIX -#endif -#if __PYX_HAS_PY_AM_SEND == 1 - #define __PYX_AM_SEND_ABI_SUFFIX -#elif __PYX_HAS_PY_AM_SEND == 2 - #define __PYX_AM_SEND_ABI_SUFFIX "amsendbackport" -#else - #define __PYX_AM_SEND_ABI_SUFFIX "noamsend" -#endif -#ifndef __PYX_MONITORING_ABI_SUFFIX - #define __PYX_MONITORING_ABI_SUFFIX -#endif -#if CYTHON_USE_TP_FINALIZE - #define __PYX_TP_FINALIZE_ABI_SUFFIX -#else - #define __PYX_TP_FINALIZE_ABI_SUFFIX "nofinalize" -#endif -#if CYTHON_USE_FREELISTS || !defined(__Pyx_AsyncGen_USED) - #define __PYX_FREELISTS_ABI_SUFFIX -#else - #define __PYX_FREELISTS_ABI_SUFFIX "nofreelists" -#endif -#define CYTHON_ABI __PYX_ABI_VERSION __PYX_LIMITED_ABI_SUFFIX __PYX_MONITORING_ABI_SUFFIX __PYX_TP_FINALIZE_ABI_SUFFIX __PYX_FREELISTS_ABI_SUFFIX __PYX_AM_SEND_ABI_SUFFIX -#define __PYX_ABI_MODULE_NAME "_cython_" CYTHON_ABI -#define __PYX_TYPE_MODULE_PREFIX __PYX_ABI_MODULE_NAME "." - - -/* Module declarations from "epanet.epanet2_ec" */ -/* #### Code section: typeinfo ### */ -/* #### Code section: before_global_var ### */ -#define __Pyx_MODULE_NAME "epanet.epanet2_ec" -extern int __pyx_module_is_main_epanet__epanet2_ec; -int __pyx_module_is_main_epanet__epanet2_ec = 0; - -/* Implementation of "epanet.epanet2_ec" */ -/* #### Code section: global_var ### */ -/* #### Code section: string_decls ### */ -static const char __pyx_k_[] = "?"; -static const char __pyx_k_0[] = "0"; -static const char __pyx_k_10[] = "10"; -static const char __pyx_k_ok[] = "ok"; -static const char __pyx_k_101[] = "101"; -static const char __pyx_k_102[] = "102"; -static const char __pyx_k_103[] = "103"; -static const char __pyx_k_104[] = "104"; -static const char __pyx_k_105[] = "105"; -static const char __pyx_k_106[] = "106"; -static const char __pyx_k_107[] = "107"; -static const char __pyx_k_108[] = "108"; -static const char __pyx_k_110[] = "110"; -static const char __pyx_k_120[] = "120"; -static const char __pyx_k_200[] = "200"; -static const char __pyx_k_201[] = "201"; -static const char __pyx_k_202[] = "202"; -static const char __pyx_k_203[] = "203"; -static const char __pyx_k_204[] = "204"; -static const char __pyx_k_205[] = "205"; -static const char __pyx_k_206[] = "206"; -static const char __pyx_k_207[] = "207"; -static const char __pyx_k_208[] = "208"; -static const char __pyx_k_209[] = "209"; -static const char __pyx_k_211[] = "211"; -static const char __pyx_k_212[] = "212"; -static const char __pyx_k_213[] = "213"; -static const char __pyx_k_214[] = "214"; -static const char __pyx_k_215[] = "215"; -static const char __pyx_k_216[] = "216"; -static const char __pyx_k_217[] = "217"; -static const char __pyx_k_219[] = "219"; -static const char __pyx_k_220[] = "220"; -static const char __pyx_k_221[] = "221"; -static const char __pyx_k_222[] = "222"; -static const char __pyx_k_223[] = "223"; -static const char __pyx_k_224[] = "224"; -static const char __pyx_k_225[] = "225"; -static const char __pyx_k_226[] = "226"; -static const char __pyx_k_227[] = "227"; -static const char __pyx_k_230[] = "230"; -static const char __pyx_k_233[] = "233"; -static const char __pyx_k_234[] = "234"; -static const char __pyx_k_240[] = "240"; -static const char __pyx_k_241[] = "241"; -static const char __pyx_k_250[] = "250"; -static const char __pyx_k_251[] = "251"; -static const char __pyx_k_252[] = "252"; -static const char __pyx_k_253[] = "253"; -static const char __pyx_k_254[] = "254"; -static const char __pyx_k_255[] = "255"; -static const char __pyx_k_257[] = "257"; -static const char __pyx_k_258[] = "258"; -static const char __pyx_k_259[] = "259"; -static const char __pyx_k_260[] = "260"; -static const char __pyx_k_261[] = "261"; -static const char __pyx_k_262[] = "262"; -static const char __pyx_k_263[] = "263"; -static const char __pyx_k_301[] = "301"; -static const char __pyx_k_302[] = "302"; -static const char __pyx_k_303[] = "303"; -static const char __pyx_k_304[] = "304"; -static const char __pyx_k_305[] = "305"; -static const char __pyx_k_306[] = "306"; -static const char __pyx_k_307[] = "307"; -static const char __pyx_k_308[] = "308"; -static const char __pyx_k_309[] = "309"; -static const char __pyx_k_411[] = "411"; -static const char __pyx_k_412[] = "412"; -static const char __pyx_k_421[] = "421"; -static const char __pyx_k_422[] = "422"; -static const char __pyx_k_423[] = "423"; -static const char __pyx_k_434[] = "434"; -static const char __pyx_k_435[] = "435"; -static const char __pyx_k_436[] = "436"; -static const char __pyx_k_ERR[] = "ERR"; -static const char __pyx_k_main[] = "__main__"; -static const char __pyx_k_name[] = "__name__"; -static const char __pyx_k_test[] = "__test__"; -static const char __pyx_k_module[] = "__module__"; -static const char __pyx_k_qualname[] = "__qualname__"; -static const char __pyx_k_ERROR_CODE[] = "ERROR_CODE"; -static const char __pyx_k_syntax_error[] = "syntax error"; -static const char __pyx_k_invalid_format[] = "invalid format"; -static const char __pyx_k_undefined_link[] = "undefined link"; -static const char __pyx_k_undefined_node[] = "undefined node"; -static const char __pyx_k_invalid_ID_name[] = "invalid ID name"; -static const char __pyx_k_undefined_curve[] = "undefined curve"; -static const char __pyx_k_nonexistent_rule[] = "nonexistent rule"; -static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback"; -static const char __pyx_k_duplicate_ID_label[] = "duplicate ID label"; -static const char __pyx_k_node_is_not_a_tank[] = "node is not a tank"; -static const char __pyx_k_nonexistent_source[] = "nonexistent source"; -static const char __pyx_k_invalid_link_vertex[] = "invalid link vertex"; -static const char __pyx_k_nonexistent_control[] = "nonexistent control"; -static const char __pyx_k_identical_file_names[] = "identical file names"; -static const char __pyx_k_invalid_option_value[] = "invalid option value"; -static const char __pyx_k_undefined_trace_node[] = "undefined trace node"; -static const char __pyx_k_illegal_numeric_value[] = "illegal numeric value"; -static const char __pyx_k_cannot_open_input_file[] = "cannot open input file"; -static const char __pyx_k_invalid_parameter_code[] = "invalid parameter code"; -static const char __pyx_k_undefined_time_pattern[] = "undefined time pattern"; -static const char __pyx_k_cannot_open_report_file[] = "cannot open report file"; -static const char __pyx_k_nonexistent_rule_clause[] = "nonexistent rule clause"; -static const char __pyx_k_invalid_pump_energy_data[] = "invalid pump energy data"; -static const char __pyx_k_node_with_no_coordinates[] = "node with no coordinates"; -static const char __pyx_k_no_network_data_available[] = "no network data available"; -static const char __pyx_k_cannot_open_hydraulics_file[] = "cannot open hydraulics file"; -static const char __pyx_k_cannot_read_hydraulics_file[] = "cannot read hydraulics file"; -static const char __pyx_k_cannot_save_results_to_file[] = "cannot save results to file"; -static const char __pyx_k_hydraulic_solver_not_opened[] = "hydraulic solver not opened"; -static const char __pyx_k_illegal_PDA_pressure_limits[] = "illegal PDA pressure limits"; -static const char __pyx_k_illegal_link_property_value[] = "illegal link property value"; -static const char __pyx_k_illegal_node_property_value[] = "illegal node property value"; -static const char __pyx_k_invalid_head_curve_for_pump[] = "invalid head curve for pump"; -static const char __pyx_k_nonexistent_demand_category[] = "nonexistent demand category"; -static const char __pyx_k_not_enough_nodes_in_network[] = "not enough nodes in network"; -static const char __pyx_k_reference_to_undefined_pump[] = "reference to undefined pump"; -static const char __pyx_k_insufficient_memory_available[] = "insufficient memory available"; -static const char __pyx_k_network_has_unconnected_nodes[] = "network has unconnected nodes"; -static const char __pyx_k_no_results_saved_to_report_on[] = "no results saved to report on"; -static const char __pyx_k_attempt_to_control_CV_GPV_link[] = "attempt to control CV/GPV link"; -static const char __pyx_k_cannot_open_binary_output_file[] = "cannot open binary output file"; -static const char __pyx_k_attempt_to_delete_node_assigned[] = "attempt to delete node assigned as a Trace Node"; -static const char __pyx_k_network_has_an_unconnected_node[] = "network has an unconnected node with ID: "; -static const char __pyx_k_no_hydraulics_for_water_quality[] = "no hydraulics for water quality analysis"; -static const char __pyx_k_water_quality_solver_not_opened[] = "water quality solver not opened"; -static const char __pyx_k_Error_An_unknown_error_has_occur[] = "Error: An unknown error has occurred"; -static const char __pyx_k_File_Error_434_unable_to_open_bi[] = "File Error 434: unable to open binary file"; -static const char __pyx_k_File_Error_435_invalid_binary_fi[] = "File Error 435: invalid binary file type"; -static const char __pyx_k_File_Error_436_no_results_in_bin[] = "File Error 436: no results in binary file"; -static const char __pyx_k_Input_Error_411_no_memory_alloca[] = "Input Error 411: no memory allocated for results"; -static const char __pyx_k_Input_Error_412_binary_file_hasn[] = "Input Error 412: binary file hasn't been opened"; -static const char __pyx_k_Input_Error_421_invalid_paramete[] = "Input Error 421: invalid parameter code"; -static const char __pyx_k_Input_Error_422_reporting_period[] = "Input Error 422: reporting period index out of range"; -static const char __pyx_k_Input_Error_423_element_index_ou[] = "Input Error 423: element index out of range"; -static const char __pyx_k_Warning_model_run_issued_warning[] = "Warning: model run issued warnings"; -static const char __pyx_k_attempt_to_delete_a_node_or_link[] = "attempt to delete a node or link contained in a control"; -static const char __pyx_k_attempt_to_delete_a_node_that_st[] = "attempt to delete a node that still has links connected to it"; -static const char __pyx_k_attempt_to_modify_network_struct[] = "attempt to modify network structure while solver is active"; -static const char __pyx_k_cannot_save_results_to_report_fi[] = "cannot save results to report file"; -static const char __pyx_k_cannot_solve_network_hydraulic_e[] = "cannot solve network hydraulic equations"; -static const char __pyx_k_cannot_solve_water_quality_trans[] = "cannot solve water quality transport equations"; -static const char __pyx_k_cannot_use_external_file_while_h[] = "cannot use external file while hydraulics solver is active"; -static const char __pyx_k_hydraulics_file_does_not_match_n[] = "hydraulics file does not match network data"; -static const char __pyx_k_hydraulics_supplied_from_externa[] = "hydraulics supplied from external file"; -static const char __pyx_k_illegal_valve_connection_to_anot[] = "illegal valve connection to another valve"; -static const char __pyx_k_illegal_valve_connection_to_tank[] = "illegal valve connection to tank node"; -static const char __pyx_k_invalid_lower_upper_levels_for_t[] = "invalid lower/upper levels for tank"; -static const char __pyx_k_mis_placed_rule_clause_in_rule_b[] = "mis-placed rule clause in rule-based control"; -static const char __pyx_k_no_head_curve_or_power_rating_fo[] = "no head curve or power rating for pump"; -static const char __pyx_k_no_tanks_or_reservoirs_in_networ[] = "no tanks or reservoirs in network"; -static const char __pyx_k_nonincreasing_x_values_for_curve[] = "nonincreasing x-values for curve"; -static const char __pyx_k_one_or_more_errors_in_input_file[] = "one or more errors in input file"; -static const char __pyx_k_same_start_and_end_nodes_for_lin[] = "same start and end nodes for link"; -static const char __pyx_k_too_many_characters_in_input_lin[] = "too many characters in input line"; -/* #### Code section: decls ### */ -/* #### Code section: late_includes ### */ -/* #### Code section: module_state ### */ -/* SmallCodeConfig */ -#ifndef CYTHON_SMALL_CODE -#if defined(__clang__) - #define CYTHON_SMALL_CODE -#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - #define CYTHON_SMALL_CODE __attribute__((cold)) -#else - #define CYTHON_SMALL_CODE -#endif -#endif - -typedef struct { - PyObject *__pyx_d; - PyObject *__pyx_b; - PyObject *__pyx_cython_runtime; - PyObject *__pyx_empty_tuple; - PyObject *__pyx_empty_bytes; - PyObject *__pyx_empty_unicode; - #ifdef __Pyx_CyFunction_USED - PyTypeObject *__pyx_CyFunctionType; - #endif - #ifdef __Pyx_FusedFunction_USED - PyTypeObject *__pyx_FusedFunctionType; - #endif - #ifdef __Pyx_Generator_USED - PyTypeObject *__pyx_GeneratorType; - #endif - #ifdef __Pyx_IterableCoroutine_USED - PyTypeObject *__pyx_IterableCoroutineType; - #endif - #ifdef __Pyx_Coroutine_USED - PyTypeObject *__pyx_CoroutineAwaitType; - #endif - #ifdef __Pyx_Coroutine_USED - PyTypeObject *__pyx_CoroutineType; - #endif - PyObject *__pyx_string_tab[156]; -/* #### Code section: module_state_contents ### */ -/* CodeObjectCache.module_state_decls */ -struct __Pyx_CodeObjectCache __pyx_code_cache; - -/* #### Code section: module_state_end ### */ -} __pyx_mstatetype; - -#if CYTHON_USE_MODULE_STATE -#ifdef __cplusplus -namespace { -extern struct PyModuleDef __pyx_moduledef; -} /* anonymous namespace */ -#else -static struct PyModuleDef __pyx_moduledef; -#endif - -#define __pyx_mstate_global (__Pyx_PyModule_GetState(__Pyx_State_FindModule(&__pyx_moduledef))) - -#define __pyx_m (__Pyx_State_FindModule(&__pyx_moduledef)) -#else -static __pyx_mstatetype __pyx_mstate_global_static = -#ifdef __cplusplus - {}; -#else - {0}; -#endif -static __pyx_mstatetype * const __pyx_mstate_global = &__pyx_mstate_global_static; -#endif -/* #### Code section: constant_name_defines ### */ -#define __pyx_kp_u_ __pyx_string_tab[0] -#define __pyx_kp_u_0 __pyx_string_tab[1] -#define __pyx_kp_u_10 __pyx_string_tab[2] -#define __pyx_kp_u_101 __pyx_string_tab[3] -#define __pyx_kp_u_102 __pyx_string_tab[4] -#define __pyx_kp_u_103 __pyx_string_tab[5] -#define __pyx_kp_u_104 __pyx_string_tab[6] -#define __pyx_kp_u_105 __pyx_string_tab[7] -#define __pyx_kp_u_106 __pyx_string_tab[8] -#define __pyx_kp_u_107 __pyx_string_tab[9] -#define __pyx_kp_u_108 __pyx_string_tab[10] -#define __pyx_kp_u_110 __pyx_string_tab[11] -#define __pyx_kp_u_120 __pyx_string_tab[12] -#define __pyx_kp_u_200 __pyx_string_tab[13] -#define __pyx_kp_u_201 __pyx_string_tab[14] -#define __pyx_kp_u_202 __pyx_string_tab[15] -#define __pyx_kp_u_203 __pyx_string_tab[16] -#define __pyx_kp_u_204 __pyx_string_tab[17] -#define __pyx_kp_u_205 __pyx_string_tab[18] -#define __pyx_kp_u_206 __pyx_string_tab[19] -#define __pyx_kp_u_207 __pyx_string_tab[20] -#define __pyx_kp_u_208 __pyx_string_tab[21] -#define __pyx_kp_u_209 __pyx_string_tab[22] -#define __pyx_kp_u_211 __pyx_string_tab[23] -#define __pyx_kp_u_212 __pyx_string_tab[24] -#define __pyx_kp_u_213 __pyx_string_tab[25] -#define __pyx_kp_u_214 __pyx_string_tab[26] -#define __pyx_kp_u_215 __pyx_string_tab[27] -#define __pyx_kp_u_216 __pyx_string_tab[28] -#define __pyx_kp_u_217 __pyx_string_tab[29] -#define __pyx_kp_u_219 __pyx_string_tab[30] -#define __pyx_kp_u_220 __pyx_string_tab[31] -#define __pyx_kp_u_221 __pyx_string_tab[32] -#define __pyx_kp_u_222 __pyx_string_tab[33] -#define __pyx_kp_u_223 __pyx_string_tab[34] -#define __pyx_kp_u_224 __pyx_string_tab[35] -#define __pyx_kp_u_225 __pyx_string_tab[36] -#define __pyx_kp_u_226 __pyx_string_tab[37] -#define __pyx_kp_u_227 __pyx_string_tab[38] -#define __pyx_kp_u_230 __pyx_string_tab[39] -#define __pyx_kp_u_233 __pyx_string_tab[40] -#define __pyx_kp_u_234 __pyx_string_tab[41] -#define __pyx_kp_u_240 __pyx_string_tab[42] -#define __pyx_kp_u_241 __pyx_string_tab[43] -#define __pyx_kp_u_250 __pyx_string_tab[44] -#define __pyx_kp_u_251 __pyx_string_tab[45] -#define __pyx_kp_u_252 __pyx_string_tab[46] -#define __pyx_kp_u_253 __pyx_string_tab[47] -#define __pyx_kp_u_254 __pyx_string_tab[48] -#define __pyx_kp_u_255 __pyx_string_tab[49] -#define __pyx_kp_u_257 __pyx_string_tab[50] -#define __pyx_kp_u_258 __pyx_string_tab[51] -#define __pyx_kp_u_259 __pyx_string_tab[52] -#define __pyx_kp_u_260 __pyx_string_tab[53] -#define __pyx_kp_u_261 __pyx_string_tab[54] -#define __pyx_kp_u_262 __pyx_string_tab[55] -#define __pyx_kp_u_263 __pyx_string_tab[56] -#define __pyx_kp_u_301 __pyx_string_tab[57] -#define __pyx_kp_u_302 __pyx_string_tab[58] -#define __pyx_kp_u_303 __pyx_string_tab[59] -#define __pyx_kp_u_304 __pyx_string_tab[60] -#define __pyx_kp_u_305 __pyx_string_tab[61] -#define __pyx_kp_u_306 __pyx_string_tab[62] -#define __pyx_kp_u_307 __pyx_string_tab[63] -#define __pyx_kp_u_308 __pyx_string_tab[64] -#define __pyx_kp_u_309 __pyx_string_tab[65] -#define __pyx_kp_u_411 __pyx_string_tab[66] -#define __pyx_kp_u_412 __pyx_string_tab[67] -#define __pyx_kp_u_421 __pyx_string_tab[68] -#define __pyx_kp_u_422 __pyx_string_tab[69] -#define __pyx_kp_u_423 __pyx_string_tab[70] -#define __pyx_kp_u_434 __pyx_string_tab[71] -#define __pyx_kp_u_435 __pyx_string_tab[72] -#define __pyx_kp_u_436 __pyx_string_tab[73] -#define __pyx_n_u_ERR __pyx_string_tab[74] -#define __pyx_n_u_ERROR_CODE __pyx_string_tab[75] -#define __pyx_kp_u_Error_An_unknown_error_has_occur __pyx_string_tab[76] -#define __pyx_kp_u_File_Error_434_unable_to_open_bi __pyx_string_tab[77] -#define __pyx_kp_u_File_Error_435_invalid_binary_fi __pyx_string_tab[78] -#define __pyx_kp_u_File_Error_436_no_results_in_bin __pyx_string_tab[79] -#define __pyx_kp_u_Input_Error_411_no_memory_alloca __pyx_string_tab[80] -#define __pyx_kp_u_Input_Error_412_binary_file_hasn __pyx_string_tab[81] -#define __pyx_kp_u_Input_Error_421_invalid_paramete __pyx_string_tab[82] -#define __pyx_kp_u_Input_Error_422_reporting_period __pyx_string_tab[83] -#define __pyx_kp_u_Input_Error_423_element_index_ou __pyx_string_tab[84] -#define __pyx_kp_u_Warning_model_run_issued_warning __pyx_string_tab[85] -#define __pyx_kp_u_attempt_to_control_CV_GPV_link __pyx_string_tab[86] -#define __pyx_kp_u_attempt_to_delete_a_node_or_link __pyx_string_tab[87] -#define __pyx_kp_u_attempt_to_delete_a_node_that_st __pyx_string_tab[88] -#define __pyx_kp_u_attempt_to_delete_node_assigned __pyx_string_tab[89] -#define __pyx_kp_u_attempt_to_modify_network_struct __pyx_string_tab[90] -#define __pyx_kp_u_cannot_open_binary_output_file __pyx_string_tab[91] -#define __pyx_kp_u_cannot_open_hydraulics_file __pyx_string_tab[92] -#define __pyx_kp_u_cannot_open_input_file __pyx_string_tab[93] -#define __pyx_kp_u_cannot_open_report_file __pyx_string_tab[94] -#define __pyx_kp_u_cannot_read_hydraulics_file __pyx_string_tab[95] -#define __pyx_kp_u_cannot_save_results_to_file __pyx_string_tab[96] -#define __pyx_kp_u_cannot_save_results_to_report_fi __pyx_string_tab[97] -#define __pyx_kp_u_cannot_solve_network_hydraulic_e __pyx_string_tab[98] -#define __pyx_kp_u_cannot_solve_water_quality_trans __pyx_string_tab[99] -#define __pyx_kp_u_cannot_use_external_file_while_h __pyx_string_tab[100] -#define __pyx_n_u_cline_in_traceback __pyx_string_tab[101] -#define __pyx_kp_u_duplicate_ID_label __pyx_string_tab[102] -#define __pyx_kp_u_hydraulic_solver_not_opened __pyx_string_tab[103] -#define __pyx_kp_u_hydraulics_file_does_not_match_n __pyx_string_tab[104] -#define __pyx_kp_u_hydraulics_supplied_from_externa __pyx_string_tab[105] -#define __pyx_kp_u_identical_file_names __pyx_string_tab[106] -#define __pyx_kp_u_illegal_PDA_pressure_limits __pyx_string_tab[107] -#define __pyx_kp_u_illegal_link_property_value __pyx_string_tab[108] -#define __pyx_kp_u_illegal_node_property_value __pyx_string_tab[109] -#define __pyx_kp_u_illegal_numeric_value __pyx_string_tab[110] -#define __pyx_kp_u_illegal_valve_connection_to_anot __pyx_string_tab[111] -#define __pyx_kp_u_illegal_valve_connection_to_tank __pyx_string_tab[112] -#define __pyx_kp_u_insufficient_memory_available __pyx_string_tab[113] -#define __pyx_kp_u_invalid_ID_name __pyx_string_tab[114] -#define __pyx_kp_u_invalid_format __pyx_string_tab[115] -#define __pyx_kp_u_invalid_head_curve_for_pump __pyx_string_tab[116] -#define __pyx_kp_u_invalid_link_vertex __pyx_string_tab[117] -#define __pyx_kp_u_invalid_lower_upper_levels_for_t __pyx_string_tab[118] -#define __pyx_kp_u_invalid_option_value __pyx_string_tab[119] -#define __pyx_kp_u_invalid_parameter_code __pyx_string_tab[120] -#define __pyx_kp_u_invalid_pump_energy_data __pyx_string_tab[121] -#define __pyx_n_u_main __pyx_string_tab[122] -#define __pyx_kp_u_mis_placed_rule_clause_in_rule_b __pyx_string_tab[123] -#define __pyx_n_u_module __pyx_string_tab[124] -#define __pyx_n_u_name __pyx_string_tab[125] -#define __pyx_kp_u_network_has_an_unconnected_node __pyx_string_tab[126] -#define __pyx_kp_u_network_has_unconnected_nodes __pyx_string_tab[127] -#define __pyx_kp_u_no_head_curve_or_power_rating_fo __pyx_string_tab[128] -#define __pyx_kp_u_no_hydraulics_for_water_quality __pyx_string_tab[129] -#define __pyx_kp_u_no_network_data_available __pyx_string_tab[130] -#define __pyx_kp_u_no_results_saved_to_report_on __pyx_string_tab[131] -#define __pyx_kp_u_no_tanks_or_reservoirs_in_networ __pyx_string_tab[132] -#define __pyx_kp_u_node_is_not_a_tank __pyx_string_tab[133] -#define __pyx_kp_u_node_with_no_coordinates __pyx_string_tab[134] -#define __pyx_kp_u_nonexistent_control __pyx_string_tab[135] -#define __pyx_kp_u_nonexistent_demand_category __pyx_string_tab[136] -#define __pyx_kp_u_nonexistent_rule __pyx_string_tab[137] -#define __pyx_kp_u_nonexistent_rule_clause __pyx_string_tab[138] -#define __pyx_kp_u_nonexistent_source __pyx_string_tab[139] -#define __pyx_kp_u_nonincreasing_x_values_for_curve __pyx_string_tab[140] -#define __pyx_kp_u_not_enough_nodes_in_network __pyx_string_tab[141] -#define __pyx_n_u_ok __pyx_string_tab[142] -#define __pyx_kp_u_one_or_more_errors_in_input_file __pyx_string_tab[143] -#define __pyx_n_u_qualname __pyx_string_tab[144] -#define __pyx_kp_u_reference_to_undefined_pump __pyx_string_tab[145] -#define __pyx_kp_u_same_start_and_end_nodes_for_lin __pyx_string_tab[146] -#define __pyx_kp_u_syntax_error __pyx_string_tab[147] -#define __pyx_n_u_test __pyx_string_tab[148] -#define __pyx_kp_u_too_many_characters_in_input_lin __pyx_string_tab[149] -#define __pyx_kp_u_undefined_curve __pyx_string_tab[150] -#define __pyx_kp_u_undefined_link __pyx_string_tab[151] -#define __pyx_kp_u_undefined_node __pyx_string_tab[152] -#define __pyx_kp_u_undefined_time_pattern __pyx_string_tab[153] -#define __pyx_kp_u_undefined_trace_node __pyx_string_tab[154] -#define __pyx_kp_u_water_quality_solver_not_opened __pyx_string_tab[155] -/* #### Code section: module_state_clear ### */ -#if CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __pyx_m_clear(PyObject *m) { - __pyx_mstatetype *clear_module_state = __Pyx_PyModule_GetState(m); - if (!clear_module_state) return 0; - Py_CLEAR(clear_module_state->__pyx_d); - Py_CLEAR(clear_module_state->__pyx_b); - Py_CLEAR(clear_module_state->__pyx_cython_runtime); - Py_CLEAR(clear_module_state->__pyx_empty_tuple); - Py_CLEAR(clear_module_state->__pyx_empty_bytes); - Py_CLEAR(clear_module_state->__pyx_empty_unicode); - #ifdef __Pyx_CyFunction_USED - Py_CLEAR(clear_module_state->__pyx_CyFunctionType); - #endif - #ifdef __Pyx_FusedFunction_USED - Py_CLEAR(clear_module_state->__pyx_FusedFunctionType); - #endif - #if CYTHON_PEP489_MULTI_PHASE_INIT - __Pyx_State_RemoveModule(NULL); - #endif - for (int i=0; i<156; ++i) { Py_CLEAR(clear_module_state->__pyx_string_tab[i]); } - return 0; -} -#endif -/* #### Code section: module_state_traverse ### */ -#if CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __pyx_m_traverse(PyObject *m, visitproc visit, void *arg) { - __pyx_mstatetype *traverse_module_state = __Pyx_PyModule_GetState(m); - if (!traverse_module_state) return 0; - Py_VISIT(traverse_module_state->__pyx_d); - Py_VISIT(traverse_module_state->__pyx_b); - Py_VISIT(traverse_module_state->__pyx_cython_runtime); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_tuple); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_bytes); - __Pyx_VISIT_CONST(traverse_module_state->__pyx_empty_unicode); - #ifdef __Pyx_CyFunction_USED - Py_VISIT(traverse_module_state->__pyx_CyFunctionType); - #endif - #ifdef __Pyx_FusedFunction_USED - Py_VISIT(traverse_module_state->__pyx_FusedFunctionType); - #endif - for (int i=0; i<156; ++i) { __Pyx_VISIT_CONST(traverse_module_state->__pyx_string_tab[i]); } - return 0; -} -#endif -/* #### Code section: module_code ### */ -/* #### Code section: module_exttypes ### */ - -static PyMethodDef __pyx_methods[] = { - {0, 0, 0, 0} -}; -/* #### Code section: initfunc_declarations ### */ -static CYTHON_SMALL_CODE int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitGlobals(void); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate); /*proto*/ -static CYTHON_SMALL_CODE int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate); /*proto*/ -/* #### Code section: init_module ### */ - -static int __Pyx_modinit_global_init_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_global_init_code", 0); - /*--- Global init code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_variable_export_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_export_code", 0); - /*--- Variable export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_export_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_function_export_code", 0); - /*--- Function export code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_type_init_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_type_init_code", 0); - /*--- Type init code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_type_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_type_import_code", 0); - /*--- Type import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_variable_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_variable_import_code", 0); - /*--- Variable import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -static int __Pyx_modinit_function_import_code(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_modinit_function_import_code", 0); - /*--- Function import code ---*/ - __Pyx_RefNannyFinishContext(); - return 0; -} - -#if CYTHON_PEP489_MULTI_PHASE_INIT -static PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def); /*proto*/ -static int __pyx_pymod_exec_epanet2_ec(PyObject* module); /*proto*/ -static PyModuleDef_Slot __pyx_moduledef_slots[] = { - {Py_mod_create, (void*)__pyx_pymod_create}, - {Py_mod_exec, (void*)__pyx_pymod_exec_epanet2_ec}, - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - {Py_mod_gil, Py_MOD_GIL_USED}, - #endif - #if PY_VERSION_HEX >= 0x030C0000 && CYTHON_USE_MODULE_STATE - {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED}, - #endif - {0, NULL} -}; -#endif - -#ifdef __cplusplus -namespace { - struct PyModuleDef __pyx_moduledef = - #else - static struct PyModuleDef __pyx_moduledef = - #endif - { - PyModuleDef_HEAD_INIT, - "epanet2_ec", - 0, /* m_doc */ - #if CYTHON_USE_MODULE_STATE - sizeof(__pyx_mstatetype), /* m_size */ - #else - (CYTHON_PEP489_MULTI_PHASE_INIT) ? 0 : -1, /* m_size */ - #endif - __pyx_methods /* m_methods */, - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_moduledef_slots, /* m_slots */ - #else - NULL, /* m_reload */ - #endif - #if CYTHON_USE_MODULE_STATE - __pyx_m_traverse, /* m_traverse */ - __pyx_m_clear, /* m_clear */ - NULL /* m_free */ - #else - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL /* m_free */ - #endif - }; - #ifdef __cplusplus -} /* anonymous namespace */ -#endif - -/* PyModInitFuncType */ -#ifndef CYTHON_NO_PYINIT_EXPORT - #define __Pyx_PyMODINIT_FUNC PyMODINIT_FUNC -#else - #ifdef __cplusplus - #define __Pyx_PyMODINIT_FUNC extern "C" PyObject * - #else - #define __Pyx_PyMODINIT_FUNC PyObject * - #endif -#endif - -__Pyx_PyMODINIT_FUNC PyInit_epanet2_ec(void) CYTHON_SMALL_CODE; /*proto*/ -__Pyx_PyMODINIT_FUNC PyInit_epanet2_ec(void) -#if CYTHON_PEP489_MULTI_PHASE_INIT -{ - return PyModuleDef_Init(&__pyx_moduledef); -} -/* ModuleCreationPEP489 */ -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x03090000 -static PY_INT64_T __Pyx_GetCurrentInterpreterId(void) { - { - PyObject *module = PyImport_ImportModule("_interpreters"); // 3.13+ I think - if (!module) { - PyErr_Clear(); // just try the 3.8-3.12 version - module = PyImport_ImportModule("_xxsubinterpreters"); - if (!module) goto bad; - } - PyObject *current = PyObject_CallMethod(module, "get_current", NULL); - Py_DECREF(module); - if (!current) goto bad; - if (PyTuple_Check(current)) { - PyObject *new_current = PySequence_GetItem(current, 0); - Py_DECREF(current); - current = new_current; - if (!new_current) goto bad; - } - long long as_c_int = PyLong_AsLongLong(current); - Py_DECREF(current); - return as_c_int; - } - bad: - PySys_WriteStderr("__Pyx_GetCurrentInterpreterId failed. Try setting the C define CYTHON_PEP489_MULTI_PHASE_INIT=0\n"); - return -1; -} -#endif -#if !CYTHON_USE_MODULE_STATE -static CYTHON_SMALL_CODE int __Pyx_check_single_interpreter(void) { - static PY_INT64_T main_interpreter_id = -1; -#if CYTHON_COMPILING_IN_GRAAL - PY_INT64_T current_id = PyInterpreterState_GetIDFromThreadState(PyThreadState_Get()); -#elif CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX >= 0x03090000 - PY_INT64_T current_id = PyInterpreterState_GetID(PyInterpreterState_Get()); -#elif CYTHON_COMPILING_IN_LIMITED_API - PY_INT64_T current_id = __Pyx_GetCurrentInterpreterId(); -#else - PY_INT64_T current_id = PyInterpreterState_GetID(PyThreadState_Get()->interp); -#endif - if (unlikely(current_id == -1)) { - return -1; - } - if (main_interpreter_id == -1) { - main_interpreter_id = current_id; - return 0; - } else if (unlikely(main_interpreter_id != current_id)) { - PyErr_SetString( - PyExc_ImportError, - "Interpreter change detected - this module can only be loaded into one interpreter per process."); - return -1; - } - return 0; -} -#endif -static CYTHON_SMALL_CODE int __Pyx_copy_spec_to_module(PyObject *spec, PyObject *moddict, const char* from_name, const char* to_name, int allow_none) -{ - PyObject *value = PyObject_GetAttrString(spec, from_name); - int result = 0; - if (likely(value)) { - if (allow_none || value != Py_None) { - result = PyDict_SetItemString(moddict, to_name, value); - } - Py_DECREF(value); - } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - } else { - result = -1; - } - return result; -} -static CYTHON_SMALL_CODE PyObject* __pyx_pymod_create(PyObject *spec, PyModuleDef *def) { - PyObject *module = NULL, *moddict, *modname; - CYTHON_UNUSED_VAR(def); - #if !CYTHON_USE_MODULE_STATE - if (__Pyx_check_single_interpreter()) - return NULL; - #endif - if (__pyx_m) - return __Pyx_NewRef(__pyx_m); - modname = PyObject_GetAttrString(spec, "name"); - if (unlikely(!modname)) goto bad; - module = PyModule_NewObject(modname); - Py_DECREF(modname); - if (unlikely(!module)) goto bad; - moddict = PyModule_GetDict(module); - if (unlikely(!moddict)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "loader", "__loader__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "origin", "__file__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "parent", "__package__", 1) < 0)) goto bad; - if (unlikely(__Pyx_copy_spec_to_module(spec, moddict, "submodule_search_locations", "__path__", 0) < 0)) goto bad; - return module; -bad: - Py_XDECREF(module); - return NULL; -} - - -static CYTHON_SMALL_CODE int __pyx_pymod_exec_epanet2_ec(PyObject *__pyx_pyinit_module) -#endif -{ - int stringtab_initialized = 0; - #if CYTHON_USE_MODULE_STATE - int pystate_addmodule_run = 0; - #endif - __pyx_mstatetype *__pyx_mstate = NULL; - PyObject *__pyx_t_1 = NULL; - PyObject *__pyx_t_2 = NULL; - int __pyx_lineno = 0; - const char *__pyx_filename = NULL; - int __pyx_clineno = 0; - __Pyx_RefNannyDeclarations - #if CYTHON_PEP489_MULTI_PHASE_INIT - if (__pyx_m) { - if (__pyx_m == __pyx_pyinit_module) return 0; - PyErr_SetString(PyExc_RuntimeError, "Module 'epanet2_ec' has already been imported. Re-initialisation is not supported."); - return -1; - } - #else - if (__pyx_m) return __Pyx_NewRef(__pyx_m); - #endif - /*--- Module creation code ---*/ - #if CYTHON_PEP489_MULTI_PHASE_INIT - __pyx_t_1 = __pyx_pyinit_module; - Py_INCREF(__pyx_t_1); - #else - __pyx_t_1 = PyModule_Create(&__pyx_moduledef); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #if CYTHON_USE_MODULE_STATE - { - int add_module_result = __Pyx_State_AddModule(__pyx_t_1, &__pyx_moduledef); - __pyx_t_1 = 0; /* transfer ownership from __pyx_t_1 to "epanet2_ec" pseudovariable */ - if (unlikely((add_module_result < 0))) __PYX_ERR(0, 1, __pyx_L1_error) - pystate_addmodule_run = 1; - } - #else - __pyx_m = __pyx_t_1; - #endif - #if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - PyUnstable_Module_SetGIL(__pyx_m, Py_MOD_GIL_USED); - #endif - __pyx_mstate = __pyx_mstate_global; - CYTHON_UNUSED_VAR(__pyx_t_1); - __pyx_mstate->__pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_mstate->__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) - Py_INCREF(__pyx_mstate->__pyx_d); - __pyx_mstate->__pyx_b = __Pyx_PyImport_AddModuleRef(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_mstate->__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_cython_runtime = __Pyx_PyImport_AddModuleRef("cython_runtime"); if (unlikely(!__pyx_mstate->__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error) - if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_mstate->__pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /* ImportRefnannyAPI */ - #if CYTHON_REFNANNY -__Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); -if (!__Pyx_RefNanny) { - PyErr_Clear(); - __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); - if (!__Pyx_RefNanny) - Py_FatalError("failed to import 'refnanny' module"); -} -#endif - -__Pyx_RefNannySetupContext("PyInit_epanet2_ec", 0); - if (__Pyx_check_binary_version(__PYX_LIMITED_VERSION_HEX, __Pyx_get_runtime_version(), CYTHON_COMPILING_IN_LIMITED_API) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pxy_PyFrame_Initialize_Offsets - __Pxy_PyFrame_Initialize_Offsets(); - #endif - __pyx_mstate->__pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_mstate->__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) - __pyx_mstate->__pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_mstate->__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) - #ifdef __Pyx_CyFunction_USED - if (__pyx_CyFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_FusedFunction_USED - if (__pyx_FusedFunction_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Coroutine_USED - if (__pyx_Coroutine_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_Generator_USED - if (__pyx_Generator_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - #ifdef __Pyx_AsyncGen_USED - if (__pyx_AsyncGen_init(__pyx_m) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - #endif - /*--- Library function declarations ---*/ - /*--- Initialize various global constants etc. ---*/ - if (__Pyx_InitConstants(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - stringtab_initialized = 1; - if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__pyx_module_is_main_epanet__epanet2_ec) { - if (PyObject_SetAttr(__pyx_m, __pyx_mstate_global->__pyx_n_u_name, __pyx_mstate_global->__pyx_n_u_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - } - { - PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) - if (!PyDict_GetItemString(modules, "epanet.epanet2_ec")) { - if (unlikely((PyDict_SetItemString(modules, "epanet.epanet2_ec", __pyx_m) < 0))) __PYX_ERR(0, 1, __pyx_L1_error) - } - } - /*--- Builtin init code ---*/ - if (__Pyx_InitCachedBuiltins(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Constants init code ---*/ - if (__Pyx_InitCachedConstants(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - if (__Pyx_CreateCodeObjects(__pyx_mstate) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - /*--- Global type/function init code ---*/ - (void)__Pyx_modinit_global_init_code(__pyx_mstate); - (void)__Pyx_modinit_variable_export_code(__pyx_mstate); - (void)__Pyx_modinit_function_export_code(__pyx_mstate); - (void)__Pyx_modinit_type_init_code(__pyx_mstate); - (void)__Pyx_modinit_type_import_code(__pyx_mstate); - (void)__Pyx_modinit_variable_import_code(__pyx_mstate); - (void)__Pyx_modinit_function_import_code(__pyx_mstate); - /*--- Execution code ---*/ - - /* "epanet/epanet2_ec.py":1 - * ERROR_CODE = {} # <<<<<<<<<<<<<< - * - * # EPANET 2 Error Messages -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_ERROR_CODE, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":4 - * - * # EPANET 2 Error Messages - * ERROR_CODE['0'] = "ok" # <<<<<<<<<<<<<< - * - * ERROR_CODE['10'] = "Warning: model run issued warnings" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 4, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_0, __pyx_mstate_global->__pyx_n_u_ok) < 0))) __PYX_ERR(0, 4, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":6 - * ERROR_CODE['0'] = "ok" - * - * ERROR_CODE['10'] = "Warning: model run issued warnings" # <<<<<<<<<<<<<< - * - * ERROR_CODE['101'] = "insufficient memory available" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 6, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_10, __pyx_mstate_global->__pyx_kp_u_Warning_model_run_issued_warning) < 0))) __PYX_ERR(0, 6, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":8 - * ERROR_CODE['10'] = "Warning: model run issued warnings" - * - * ERROR_CODE['101'] = "insufficient memory available" # <<<<<<<<<<<<<< - * ERROR_CODE['102'] = "no network data available" - * ERROR_CODE['103'] = "hydraulic solver not opened" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 8, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_101, __pyx_mstate_global->__pyx_kp_u_insufficient_memory_available) < 0))) __PYX_ERR(0, 8, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":9 - * - * ERROR_CODE['101'] = "insufficient memory available" - * ERROR_CODE['102'] = "no network data available" # <<<<<<<<<<<<<< - * ERROR_CODE['103'] = "hydraulic solver not opened" - * ERROR_CODE['104'] = "no hydraulics for water quality analysis" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_102, __pyx_mstate_global->__pyx_kp_u_no_network_data_available) < 0))) __PYX_ERR(0, 9, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":10 - * ERROR_CODE['101'] = "insufficient memory available" - * ERROR_CODE['102'] = "no network data available" - * ERROR_CODE['103'] = "hydraulic solver not opened" # <<<<<<<<<<<<<< - * ERROR_CODE['104'] = "no hydraulics for water quality analysis" - * ERROR_CODE['105'] = "water quality solver not opened" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 10, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_103, __pyx_mstate_global->__pyx_kp_u_hydraulic_solver_not_opened) < 0))) __PYX_ERR(0, 10, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":11 - * ERROR_CODE['102'] = "no network data available" - * ERROR_CODE['103'] = "hydraulic solver not opened" - * ERROR_CODE['104'] = "no hydraulics for water quality analysis" # <<<<<<<<<<<<<< - * ERROR_CODE['105'] = "water quality solver not opened" - * ERROR_CODE['106'] = "no results saved to report on" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_104, __pyx_mstate_global->__pyx_kp_u_no_hydraulics_for_water_quality) < 0))) __PYX_ERR(0, 11, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":12 - * ERROR_CODE['103'] = "hydraulic solver not opened" - * ERROR_CODE['104'] = "no hydraulics for water quality analysis" - * ERROR_CODE['105'] = "water quality solver not opened" # <<<<<<<<<<<<<< - * ERROR_CODE['106'] = "no results saved to report on" - * ERROR_CODE['107'] = "hydraulics supplied from external file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 12, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_105, __pyx_mstate_global->__pyx_kp_u_water_quality_solver_not_opened) < 0))) __PYX_ERR(0, 12, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":13 - * ERROR_CODE['104'] = "no hydraulics for water quality analysis" - * ERROR_CODE['105'] = "water quality solver not opened" - * ERROR_CODE['106'] = "no results saved to report on" # <<<<<<<<<<<<<< - * ERROR_CODE['107'] = "hydraulics supplied from external file" - * ERROR_CODE['108'] = "cannot use external file while hydraulics solver is active" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 13, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_106, __pyx_mstate_global->__pyx_kp_u_no_results_saved_to_report_on) < 0))) __PYX_ERR(0, 13, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":14 - * ERROR_CODE['105'] = "water quality solver not opened" - * ERROR_CODE['106'] = "no results saved to report on" - * ERROR_CODE['107'] = "hydraulics supplied from external file" # <<<<<<<<<<<<<< - * ERROR_CODE['108'] = "cannot use external file while hydraulics solver is active" - * ERROR_CODE['110'] = "cannot solve network hydraulic equations" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 14, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_107, __pyx_mstate_global->__pyx_kp_u_hydraulics_supplied_from_externa) < 0))) __PYX_ERR(0, 14, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":15 - * ERROR_CODE['106'] = "no results saved to report on" - * ERROR_CODE['107'] = "hydraulics supplied from external file" - * ERROR_CODE['108'] = "cannot use external file while hydraulics solver is active" # <<<<<<<<<<<<<< - * ERROR_CODE['110'] = "cannot solve network hydraulic equations" - * ERROR_CODE['120'] = "cannot solve water quality transport equations" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 15, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_108, __pyx_mstate_global->__pyx_kp_u_cannot_use_external_file_while_h) < 0))) __PYX_ERR(0, 15, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":16 - * ERROR_CODE['107'] = "hydraulics supplied from external file" - * ERROR_CODE['108'] = "cannot use external file while hydraulics solver is active" - * ERROR_CODE['110'] = "cannot solve network hydraulic equations" # <<<<<<<<<<<<<< - * ERROR_CODE['120'] = "cannot solve water quality transport equations" - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_110, __pyx_mstate_global->__pyx_kp_u_cannot_solve_network_hydraulic_e) < 0))) __PYX_ERR(0, 16, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":17 - * ERROR_CODE['108'] = "cannot use external file while hydraulics solver is active" - * ERROR_CODE['110'] = "cannot solve network hydraulic equations" - * ERROR_CODE['120'] = "cannot solve water quality transport equations" # <<<<<<<<<<<<<< - * - * # These errors apply only to an input file -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 17, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_120, __pyx_mstate_global->__pyx_kp_u_cannot_solve_water_quality_trans) < 0))) __PYX_ERR(0, 17, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":20 - * - * # These errors apply only to an input file - * ERROR_CODE['200'] = "one or more errors in input file" # <<<<<<<<<<<<<< - * ERROR_CODE['201'] = "syntax error" - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 20, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_200, __pyx_mstate_global->__pyx_kp_u_one_or_more_errors_in_input_file) < 0))) __PYX_ERR(0, 20, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":21 - * # These errors apply only to an input file - * ERROR_CODE['200'] = "one or more errors in input file" - * ERROR_CODE['201'] = "syntax error" # <<<<<<<<<<<<<< - * - * # These errors apply to both an input file and to API functions -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 21, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_201, __pyx_mstate_global->__pyx_kp_u_syntax_error) < 0))) __PYX_ERR(0, 21, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":24 - * - * # These errors apply to both an input file and to API functions - * ERROR_CODE['202'] = "illegal numeric value" # <<<<<<<<<<<<<< - * ERROR_CODE['203'] = "undefined node" - * ERROR_CODE['204'] = "undefined link" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 24, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_202, __pyx_mstate_global->__pyx_kp_u_illegal_numeric_value) < 0))) __PYX_ERR(0, 24, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":25 - * # These errors apply to both an input file and to API functions - * ERROR_CODE['202'] = "illegal numeric value" - * ERROR_CODE['203'] = "undefined node" # <<<<<<<<<<<<<< - * ERROR_CODE['204'] = "undefined link" - * ERROR_CODE['205'] = "undefined time pattern" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 25, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_203, __pyx_mstate_global->__pyx_kp_u_undefined_node) < 0))) __PYX_ERR(0, 25, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":26 - * ERROR_CODE['202'] = "illegal numeric value" - * ERROR_CODE['203'] = "undefined node" - * ERROR_CODE['204'] = "undefined link" # <<<<<<<<<<<<<< - * ERROR_CODE['205'] = "undefined time pattern" - * ERROR_CODE['206'] = "undefined curve" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 26, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_204, __pyx_mstate_global->__pyx_kp_u_undefined_link) < 0))) __PYX_ERR(0, 26, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":27 - * ERROR_CODE['203'] = "undefined node" - * ERROR_CODE['204'] = "undefined link" - * ERROR_CODE['205'] = "undefined time pattern" # <<<<<<<<<<<<<< - * ERROR_CODE['206'] = "undefined curve" - * ERROR_CODE['207'] = "attempt to control CV/GPV link" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_205, __pyx_mstate_global->__pyx_kp_u_undefined_time_pattern) < 0))) __PYX_ERR(0, 27, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":28 - * ERROR_CODE['204'] = "undefined link" - * ERROR_CODE['205'] = "undefined time pattern" - * ERROR_CODE['206'] = "undefined curve" # <<<<<<<<<<<<<< - * ERROR_CODE['207'] = "attempt to control CV/GPV link" - * ERROR_CODE['208'] = "illegal PDA pressure limits" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 28, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_206, __pyx_mstate_global->__pyx_kp_u_undefined_curve) < 0))) __PYX_ERR(0, 28, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":29 - * ERROR_CODE['205'] = "undefined time pattern" - * ERROR_CODE['206'] = "undefined curve" - * ERROR_CODE['207'] = "attempt to control CV/GPV link" # <<<<<<<<<<<<<< - * ERROR_CODE['208'] = "illegal PDA pressure limits" - * ERROR_CODE['209'] = "illegal node property value" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 29, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_207, __pyx_mstate_global->__pyx_kp_u_attempt_to_control_CV_GPV_link) < 0))) __PYX_ERR(0, 29, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":30 - * ERROR_CODE['206'] = "undefined curve" - * ERROR_CODE['207'] = "attempt to control CV/GPV link" - * ERROR_CODE['208'] = "illegal PDA pressure limits" # <<<<<<<<<<<<<< - * ERROR_CODE['209'] = "illegal node property value" - * ERROR_CODE['211'] = "illegal link property value" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_208, __pyx_mstate_global->__pyx_kp_u_illegal_PDA_pressure_limits) < 0))) __PYX_ERR(0, 30, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":31 - * ERROR_CODE['207'] = "attempt to control CV/GPV link" - * ERROR_CODE['208'] = "illegal PDA pressure limits" - * ERROR_CODE['209'] = "illegal node property value" # <<<<<<<<<<<<<< - * ERROR_CODE['211'] = "illegal link property value" - * ERROR_CODE['212'] = "undefined trace node" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 31, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_209, __pyx_mstate_global->__pyx_kp_u_illegal_node_property_value) < 0))) __PYX_ERR(0, 31, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":32 - * ERROR_CODE['208'] = "illegal PDA pressure limits" - * ERROR_CODE['209'] = "illegal node property value" - * ERROR_CODE['211'] = "illegal link property value" # <<<<<<<<<<<<<< - * ERROR_CODE['212'] = "undefined trace node" - * ERROR_CODE['213'] = "invalid option value" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_211, __pyx_mstate_global->__pyx_kp_u_illegal_link_property_value) < 0))) __PYX_ERR(0, 32, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":33 - * ERROR_CODE['209'] = "illegal node property value" - * ERROR_CODE['211'] = "illegal link property value" - * ERROR_CODE['212'] = "undefined trace node" # <<<<<<<<<<<<<< - * ERROR_CODE['213'] = "invalid option value" - * ERROR_CODE['214'] = "too many characters in input line" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 33, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_212, __pyx_mstate_global->__pyx_kp_u_undefined_trace_node) < 0))) __PYX_ERR(0, 33, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":34 - * ERROR_CODE['211'] = "illegal link property value" - * ERROR_CODE['212'] = "undefined trace node" - * ERROR_CODE['213'] = "invalid option value" # <<<<<<<<<<<<<< - * ERROR_CODE['214'] = "too many characters in input line" - * ERROR_CODE['215'] = "duplicate ID label" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 34, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_213, __pyx_mstate_global->__pyx_kp_u_invalid_option_value) < 0))) __PYX_ERR(0, 34, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":35 - * ERROR_CODE['212'] = "undefined trace node" - * ERROR_CODE['213'] = "invalid option value" - * ERROR_CODE['214'] = "too many characters in input line" # <<<<<<<<<<<<<< - * ERROR_CODE['215'] = "duplicate ID label" - * ERROR_CODE['216'] = "reference to undefined pump" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 35, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_214, __pyx_mstate_global->__pyx_kp_u_too_many_characters_in_input_lin) < 0))) __PYX_ERR(0, 35, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":36 - * ERROR_CODE['213'] = "invalid option value" - * ERROR_CODE['214'] = "too many characters in input line" - * ERROR_CODE['215'] = "duplicate ID label" # <<<<<<<<<<<<<< - * ERROR_CODE['216'] = "reference to undefined pump" - * ERROR_CODE['217'] = "invalid pump energy data" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_215, __pyx_mstate_global->__pyx_kp_u_duplicate_ID_label) < 0))) __PYX_ERR(0, 36, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":37 - * ERROR_CODE['214'] = "too many characters in input line" - * ERROR_CODE['215'] = "duplicate ID label" - * ERROR_CODE['216'] = "reference to undefined pump" # <<<<<<<<<<<<<< - * ERROR_CODE['217'] = "invalid pump energy data" - * ERROR_CODE['219'] = "illegal valve connection to tank node" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_216, __pyx_mstate_global->__pyx_kp_u_reference_to_undefined_pump) < 0))) __PYX_ERR(0, 37, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":38 - * ERROR_CODE['215'] = "duplicate ID label" - * ERROR_CODE['216'] = "reference to undefined pump" - * ERROR_CODE['217'] = "invalid pump energy data" # <<<<<<<<<<<<<< - * ERROR_CODE['219'] = "illegal valve connection to tank node" - * ERROR_CODE['220'] = "illegal valve connection to another valve" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 38, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_217, __pyx_mstate_global->__pyx_kp_u_invalid_pump_energy_data) < 0))) __PYX_ERR(0, 38, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":39 - * ERROR_CODE['216'] = "reference to undefined pump" - * ERROR_CODE['217'] = "invalid pump energy data" - * ERROR_CODE['219'] = "illegal valve connection to tank node" # <<<<<<<<<<<<<< - * ERROR_CODE['220'] = "illegal valve connection to another valve" - * ERROR_CODE['221'] = "mis-placed rule clause in rule-based control" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 39, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_219, __pyx_mstate_global->__pyx_kp_u_illegal_valve_connection_to_tank) < 0))) __PYX_ERR(0, 39, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":40 - * ERROR_CODE['217'] = "invalid pump energy data" - * ERROR_CODE['219'] = "illegal valve connection to tank node" - * ERROR_CODE['220'] = "illegal valve connection to another valve" # <<<<<<<<<<<<<< - * ERROR_CODE['221'] = "mis-placed rule clause in rule-based control" - * ERROR_CODE['222'] = "same start and end nodes for link" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 40, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_220, __pyx_mstate_global->__pyx_kp_u_illegal_valve_connection_to_anot) < 0))) __PYX_ERR(0, 40, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":41 - * ERROR_CODE['219'] = "illegal valve connection to tank node" - * ERROR_CODE['220'] = "illegal valve connection to another valve" - * ERROR_CODE['221'] = "mis-placed rule clause in rule-based control" # <<<<<<<<<<<<<< - * ERROR_CODE['222'] = "same start and end nodes for link" - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 41, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_221, __pyx_mstate_global->__pyx_kp_u_mis_placed_rule_clause_in_rule_b) < 0))) __PYX_ERR(0, 41, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":42 - * ERROR_CODE['220'] = "illegal valve connection to another valve" - * ERROR_CODE['221'] = "mis-placed rule clause in rule-based control" - * ERROR_CODE['222'] = "same start and end nodes for link" # <<<<<<<<<<<<<< - * - * # These errors apply to network consistency check -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 42, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_222, __pyx_mstate_global->__pyx_kp_u_same_start_and_end_nodes_for_lin) < 0))) __PYX_ERR(0, 42, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":45 - * - * # These errors apply to network consistency check - * ERROR_CODE['223'] = "not enough nodes in network" # <<<<<<<<<<<<<< - * ERROR_CODE['224'] = "no tanks or reservoirs in network" - * ERROR_CODE['225'] = "invalid lower/upper levels for tank" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 45, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_223, __pyx_mstate_global->__pyx_kp_u_not_enough_nodes_in_network) < 0))) __PYX_ERR(0, 45, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":46 - * # These errors apply to network consistency check - * ERROR_CODE['223'] = "not enough nodes in network" - * ERROR_CODE['224'] = "no tanks or reservoirs in network" # <<<<<<<<<<<<<< - * ERROR_CODE['225'] = "invalid lower/upper levels for tank" - * ERROR_CODE['226'] = "no head curve or power rating for pump" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_224, __pyx_mstate_global->__pyx_kp_u_no_tanks_or_reservoirs_in_networ) < 0))) __PYX_ERR(0, 46, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":47 - * ERROR_CODE['223'] = "not enough nodes in network" - * ERROR_CODE['224'] = "no tanks or reservoirs in network" - * ERROR_CODE['225'] = "invalid lower/upper levels for tank" # <<<<<<<<<<<<<< - * ERROR_CODE['226'] = "no head curve or power rating for pump" - * ERROR_CODE['227'] = "invalid head curve for pump" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 47, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_225, __pyx_mstate_global->__pyx_kp_u_invalid_lower_upper_levels_for_t) < 0))) __PYX_ERR(0, 47, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":48 - * ERROR_CODE['224'] = "no tanks or reservoirs in network" - * ERROR_CODE['225'] = "invalid lower/upper levels for tank" - * ERROR_CODE['226'] = "no head curve or power rating for pump" # <<<<<<<<<<<<<< - * ERROR_CODE['227'] = "invalid head curve for pump" - * ERROR_CODE['230'] = "nonincreasing x-values for curve" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 48, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_226, __pyx_mstate_global->__pyx_kp_u_no_head_curve_or_power_rating_fo) < 0))) __PYX_ERR(0, 48, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":49 - * ERROR_CODE['225'] = "invalid lower/upper levels for tank" - * ERROR_CODE['226'] = "no head curve or power rating for pump" - * ERROR_CODE['227'] = "invalid head curve for pump" # <<<<<<<<<<<<<< - * ERROR_CODE['230'] = "nonincreasing x-values for curve" - * ERROR_CODE['233'] = "network has unconnected nodes" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 49, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_227, __pyx_mstate_global->__pyx_kp_u_invalid_head_curve_for_pump) < 0))) __PYX_ERR(0, 49, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":50 - * ERROR_CODE['226'] = "no head curve or power rating for pump" - * ERROR_CODE['227'] = "invalid head curve for pump" - * ERROR_CODE['230'] = "nonincreasing x-values for curve" # <<<<<<<<<<<<<< - * ERROR_CODE['233'] = "network has unconnected nodes" - * ERROR_CODE['234'] = "network has an unconnected node with ID: " -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 50, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_230, __pyx_mstate_global->__pyx_kp_u_nonincreasing_x_values_for_curve) < 0))) __PYX_ERR(0, 50, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":51 - * ERROR_CODE['227'] = "invalid head curve for pump" - * ERROR_CODE['230'] = "nonincreasing x-values for curve" - * ERROR_CODE['233'] = "network has unconnected nodes" # <<<<<<<<<<<<<< - * ERROR_CODE['234'] = "network has an unconnected node with ID: " - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 51, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_233, __pyx_mstate_global->__pyx_kp_u_network_has_unconnected_nodes) < 0))) __PYX_ERR(0, 51, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":52 - * ERROR_CODE['230'] = "nonincreasing x-values for curve" - * ERROR_CODE['233'] = "network has unconnected nodes" - * ERROR_CODE['234'] = "network has an unconnected node with ID: " # <<<<<<<<<<<<<< - * - * # These errors apply only to API functions -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 52, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_234, __pyx_mstate_global->__pyx_kp_u_network_has_an_unconnected_node) < 0))) __PYX_ERR(0, 52, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":55 - * - * # These errors apply only to API functions - * ERROR_CODE['240'] = "nonexistent source" # <<<<<<<<<<<<<< - * ERROR_CODE['241'] = "nonexistent control" - * ERROR_CODE['250'] = "invalid format" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_240, __pyx_mstate_global->__pyx_kp_u_nonexistent_source) < 0))) __PYX_ERR(0, 55, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":56 - * # These errors apply only to API functions - * ERROR_CODE['240'] = "nonexistent source" - * ERROR_CODE['241'] = "nonexistent control" # <<<<<<<<<<<<<< - * ERROR_CODE['250'] = "invalid format" - * ERROR_CODE['251'] = "invalid parameter code" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 56, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_241, __pyx_mstate_global->__pyx_kp_u_nonexistent_control) < 0))) __PYX_ERR(0, 56, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":57 - * ERROR_CODE['240'] = "nonexistent source" - * ERROR_CODE['241'] = "nonexistent control" - * ERROR_CODE['250'] = "invalid format" # <<<<<<<<<<<<<< - * ERROR_CODE['251'] = "invalid parameter code" - * ERROR_CODE['252'] = "invalid ID name" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 57, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_250, __pyx_mstate_global->__pyx_kp_u_invalid_format) < 0))) __PYX_ERR(0, 57, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":58 - * ERROR_CODE['241'] = "nonexistent control" - * ERROR_CODE['250'] = "invalid format" - * ERROR_CODE['251'] = "invalid parameter code" # <<<<<<<<<<<<<< - * ERROR_CODE['252'] = "invalid ID name" - * ERROR_CODE['253'] = "nonexistent demand category" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 58, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_251, __pyx_mstate_global->__pyx_kp_u_invalid_parameter_code) < 0))) __PYX_ERR(0, 58, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":59 - * ERROR_CODE['250'] = "invalid format" - * ERROR_CODE['251'] = "invalid parameter code" - * ERROR_CODE['252'] = "invalid ID name" # <<<<<<<<<<<<<< - * ERROR_CODE['253'] = "nonexistent demand category" - * ERROR_CODE['254'] = "node with no coordinates" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_252, __pyx_mstate_global->__pyx_kp_u_invalid_ID_name) < 0))) __PYX_ERR(0, 59, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":60 - * ERROR_CODE['251'] = "invalid parameter code" - * ERROR_CODE['252'] = "invalid ID name" - * ERROR_CODE['253'] = "nonexistent demand category" # <<<<<<<<<<<<<< - * ERROR_CODE['254'] = "node with no coordinates" - * ERROR_CODE['255'] = "invalid link vertex" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_253, __pyx_mstate_global->__pyx_kp_u_nonexistent_demand_category) < 0))) __PYX_ERR(0, 60, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":61 - * ERROR_CODE['252'] = "invalid ID name" - * ERROR_CODE['253'] = "nonexistent demand category" - * ERROR_CODE['254'] = "node with no coordinates" # <<<<<<<<<<<<<< - * ERROR_CODE['255'] = "invalid link vertex" - * ERROR_CODE['257'] = "nonexistent rule" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 61, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_254, __pyx_mstate_global->__pyx_kp_u_node_with_no_coordinates) < 0))) __PYX_ERR(0, 61, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":62 - * ERROR_CODE['253'] = "nonexistent demand category" - * ERROR_CODE['254'] = "node with no coordinates" - * ERROR_CODE['255'] = "invalid link vertex" # <<<<<<<<<<<<<< - * ERROR_CODE['257'] = "nonexistent rule" - * ERROR_CODE['258'] = "nonexistent rule clause" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_255, __pyx_mstate_global->__pyx_kp_u_invalid_link_vertex) < 0))) __PYX_ERR(0, 62, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":63 - * ERROR_CODE['254'] = "node with no coordinates" - * ERROR_CODE['255'] = "invalid link vertex" - * ERROR_CODE['257'] = "nonexistent rule" # <<<<<<<<<<<<<< - * ERROR_CODE['258'] = "nonexistent rule clause" - * ERROR_CODE['259'] = "attempt to delete a node that still has links connected to it" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 63, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_257, __pyx_mstate_global->__pyx_kp_u_nonexistent_rule) < 0))) __PYX_ERR(0, 63, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":64 - * ERROR_CODE['255'] = "invalid link vertex" - * ERROR_CODE['257'] = "nonexistent rule" - * ERROR_CODE['258'] = "nonexistent rule clause" # <<<<<<<<<<<<<< - * ERROR_CODE['259'] = "attempt to delete a node that still has links connected to it" - * ERROR_CODE['260'] = "attempt to delete node assigned as a Trace Node" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 64, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_258, __pyx_mstate_global->__pyx_kp_u_nonexistent_rule_clause) < 0))) __PYX_ERR(0, 64, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":65 - * ERROR_CODE['257'] = "nonexistent rule" - * ERROR_CODE['258'] = "nonexistent rule clause" - * ERROR_CODE['259'] = "attempt to delete a node that still has links connected to it" # <<<<<<<<<<<<<< - * ERROR_CODE['260'] = "attempt to delete node assigned as a Trace Node" - * ERROR_CODE['261'] = "attempt to delete a node or link contained in a control" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 65, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_259, __pyx_mstate_global->__pyx_kp_u_attempt_to_delete_a_node_that_st) < 0))) __PYX_ERR(0, 65, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":66 - * ERROR_CODE['258'] = "nonexistent rule clause" - * ERROR_CODE['259'] = "attempt to delete a node that still has links connected to it" - * ERROR_CODE['260'] = "attempt to delete node assigned as a Trace Node" # <<<<<<<<<<<<<< - * ERROR_CODE['261'] = "attempt to delete a node or link contained in a control" - * ERROR_CODE['262'] = "attempt to modify network structure while solver is active" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 66, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_260, __pyx_mstate_global->__pyx_kp_u_attempt_to_delete_node_assigned) < 0))) __PYX_ERR(0, 66, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":67 - * ERROR_CODE['259'] = "attempt to delete a node that still has links connected to it" - * ERROR_CODE['260'] = "attempt to delete node assigned as a Trace Node" - * ERROR_CODE['261'] = "attempt to delete a node or link contained in a control" # <<<<<<<<<<<<<< - * ERROR_CODE['262'] = "attempt to modify network structure while solver is active" - * ERROR_CODE['263'] = "node is not a tank" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 67, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_261, __pyx_mstate_global->__pyx_kp_u_attempt_to_delete_a_node_or_link) < 0))) __PYX_ERR(0, 67, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":68 - * ERROR_CODE['260'] = "attempt to delete node assigned as a Trace Node" - * ERROR_CODE['261'] = "attempt to delete a node or link contained in a control" - * ERROR_CODE['262'] = "attempt to modify network structure while solver is active" # <<<<<<<<<<<<<< - * ERROR_CODE['263'] = "node is not a tank" - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 68, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_262, __pyx_mstate_global->__pyx_kp_u_attempt_to_modify_network_struct) < 0))) __PYX_ERR(0, 68, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":69 - * ERROR_CODE['261'] = "attempt to delete a node or link contained in a control" - * ERROR_CODE['262'] = "attempt to modify network structure while solver is active" - * ERROR_CODE['263'] = "node is not a tank" # <<<<<<<<<<<<<< - * - * # File errors -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 69, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_263, __pyx_mstate_global->__pyx_kp_u_node_is_not_a_tank) < 0))) __PYX_ERR(0, 69, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":72 - * - * # File errors - * ERROR_CODE['301'] = "identical file names" # <<<<<<<<<<<<<< - * ERROR_CODE['302'] = "cannot open input file" - * ERROR_CODE['303'] = "cannot open report file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 72, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_301, __pyx_mstate_global->__pyx_kp_u_identical_file_names) < 0))) __PYX_ERR(0, 72, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":73 - * # File errors - * ERROR_CODE['301'] = "identical file names" - * ERROR_CODE['302'] = "cannot open input file" # <<<<<<<<<<<<<< - * ERROR_CODE['303'] = "cannot open report file" - * ERROR_CODE['304'] = "cannot open binary output file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 73, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_302, __pyx_mstate_global->__pyx_kp_u_cannot_open_input_file) < 0))) __PYX_ERR(0, 73, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":74 - * ERROR_CODE['301'] = "identical file names" - * ERROR_CODE['302'] = "cannot open input file" - * ERROR_CODE['303'] = "cannot open report file" # <<<<<<<<<<<<<< - * ERROR_CODE['304'] = "cannot open binary output file" - * ERROR_CODE['305'] = "cannot open hydraulics file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 74, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_303, __pyx_mstate_global->__pyx_kp_u_cannot_open_report_file) < 0))) __PYX_ERR(0, 74, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":75 - * ERROR_CODE['302'] = "cannot open input file" - * ERROR_CODE['303'] = "cannot open report file" - * ERROR_CODE['304'] = "cannot open binary output file" # <<<<<<<<<<<<<< - * ERROR_CODE['305'] = "cannot open hydraulics file" - * ERROR_CODE['306'] = "hydraulics file does not match network data" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 75, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_304, __pyx_mstate_global->__pyx_kp_u_cannot_open_binary_output_file) < 0))) __PYX_ERR(0, 75, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":76 - * ERROR_CODE['303'] = "cannot open report file" - * ERROR_CODE['304'] = "cannot open binary output file" - * ERROR_CODE['305'] = "cannot open hydraulics file" # <<<<<<<<<<<<<< - * ERROR_CODE['306'] = "hydraulics file does not match network data" - * ERROR_CODE['307'] = "cannot read hydraulics file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_305, __pyx_mstate_global->__pyx_kp_u_cannot_open_hydraulics_file) < 0))) __PYX_ERR(0, 76, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":77 - * ERROR_CODE['304'] = "cannot open binary output file" - * ERROR_CODE['305'] = "cannot open hydraulics file" - * ERROR_CODE['306'] = "hydraulics file does not match network data" # <<<<<<<<<<<<<< - * ERROR_CODE['307'] = "cannot read hydraulics file" - * ERROR_CODE['308'] = "cannot save results to file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_306, __pyx_mstate_global->__pyx_kp_u_hydraulics_file_does_not_match_n) < 0))) __PYX_ERR(0, 77, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":78 - * ERROR_CODE['305'] = "cannot open hydraulics file" - * ERROR_CODE['306'] = "hydraulics file does not match network data" - * ERROR_CODE['307'] = "cannot read hydraulics file" # <<<<<<<<<<<<<< - * ERROR_CODE['308'] = "cannot save results to file" - * ERROR_CODE['309'] = "cannot save results to report file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_307, __pyx_mstate_global->__pyx_kp_u_cannot_read_hydraulics_file) < 0))) __PYX_ERR(0, 78, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":79 - * ERROR_CODE['306'] = "hydraulics file does not match network data" - * ERROR_CODE['307'] = "cannot read hydraulics file" - * ERROR_CODE['308'] = "cannot save results to file" # <<<<<<<<<<<<<< - * ERROR_CODE['309'] = "cannot save results to report file" - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_308, __pyx_mstate_global->__pyx_kp_u_cannot_save_results_to_file) < 0))) __PYX_ERR(0, 79, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":80 - * ERROR_CODE['307'] = "cannot read hydraulics file" - * ERROR_CODE['308'] = "cannot save results to file" - * ERROR_CODE['309'] = "cannot save results to report file" # <<<<<<<<<<<<<< - * - * ERROR_CODE['411'] = "Input Error 411: no memory allocated for results" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_309, __pyx_mstate_global->__pyx_kp_u_cannot_save_results_to_report_fi) < 0))) __PYX_ERR(0, 80, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":82 - * ERROR_CODE['309'] = "cannot save results to report file" - * - * ERROR_CODE['411'] = "Input Error 411: no memory allocated for results" # <<<<<<<<<<<<<< - * ERROR_CODE['412'] = "Input Error 412: binary file hasn't been opened" - * ERROR_CODE['421'] = "Input Error 421: invalid parameter code" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 82, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_411, __pyx_mstate_global->__pyx_kp_u_Input_Error_411_no_memory_alloca) < 0))) __PYX_ERR(0, 82, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":83 - * - * ERROR_CODE['411'] = "Input Error 411: no memory allocated for results" - * ERROR_CODE['412'] = "Input Error 412: binary file hasn't been opened" # <<<<<<<<<<<<<< - * ERROR_CODE['421'] = "Input Error 421: invalid parameter code" - * ERROR_CODE['422'] = "Input Error 422: reporting period index out of range" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 83, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_412, __pyx_mstate_global->__pyx_kp_u_Input_Error_412_binary_file_hasn) < 0))) __PYX_ERR(0, 83, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":84 - * ERROR_CODE['411'] = "Input Error 411: no memory allocated for results" - * ERROR_CODE['412'] = "Input Error 412: binary file hasn't been opened" - * ERROR_CODE['421'] = "Input Error 421: invalid parameter code" # <<<<<<<<<<<<<< - * ERROR_CODE['422'] = "Input Error 422: reporting period index out of range" - * ERROR_CODE['423'] = "Input Error 423: element index out of range" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 84, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_421, __pyx_mstate_global->__pyx_kp_u_Input_Error_421_invalid_paramete) < 0))) __PYX_ERR(0, 84, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":85 - * ERROR_CODE['412'] = "Input Error 412: binary file hasn't been opened" - * ERROR_CODE['421'] = "Input Error 421: invalid parameter code" - * ERROR_CODE['422'] = "Input Error 422: reporting period index out of range" # <<<<<<<<<<<<<< - * ERROR_CODE['423'] = "Input Error 423: element index out of range" - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 85, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_422, __pyx_mstate_global->__pyx_kp_u_Input_Error_422_reporting_period) < 0))) __PYX_ERR(0, 85, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":86 - * ERROR_CODE['421'] = "Input Error 421: invalid parameter code" - * ERROR_CODE['422'] = "Input Error 422: reporting period index out of range" - * ERROR_CODE['423'] = "Input Error 423: element index out of range" # <<<<<<<<<<<<<< - * - * ERROR_CODE['434'] = "File Error 434: unable to open binary file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 86, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_423, __pyx_mstate_global->__pyx_kp_u_Input_Error_423_element_index_ou) < 0))) __PYX_ERR(0, 86, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":88 - * ERROR_CODE['423'] = "Input Error 423: element index out of range" - * - * ERROR_CODE['434'] = "File Error 434: unable to open binary file" # <<<<<<<<<<<<<< - * ERROR_CODE['435'] = "File Error 435: invalid binary file type" - * ERROR_CODE['436'] = "File Error 436: no results in binary file" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_434, __pyx_mstate_global->__pyx_kp_u_File_Error_434_unable_to_open_bi) < 0))) __PYX_ERR(0, 88, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":89 - * - * ERROR_CODE['434'] = "File Error 434: unable to open binary file" - * ERROR_CODE['435'] = "File Error 435: invalid binary file type" # <<<<<<<<<<<<<< - * ERROR_CODE['436'] = "File Error 436: no results in binary file" - * -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 89, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_435, __pyx_mstate_global->__pyx_kp_u_File_Error_435_invalid_binary_fi) < 0))) __PYX_ERR(0, 89, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":90 - * ERROR_CODE['434'] = "File Error 434: unable to open binary file" - * ERROR_CODE['435'] = "File Error 435: invalid binary file type" - * ERROR_CODE['436'] = "File Error 436: no results in binary file" # <<<<<<<<<<<<<< - * - * ERROR_CODE['ERR'] = "Error: An unknown error has occurred" -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 90, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_436, __pyx_mstate_global->__pyx_kp_u_File_Error_436_no_results_in_bin) < 0))) __PYX_ERR(0, 90, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":92 - * ERROR_CODE['436'] = "File Error 436: no results in binary file" - * - * ERROR_CODE['ERR'] = "Error: An unknown error has occurred" # <<<<<<<<<<<<<< -*/ - __Pyx_GetModuleGlobalName(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERROR_CODE); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 92, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (unlikely((PyObject_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_ERR, __pyx_mstate_global->__pyx_kp_u_Error_An_unknown_error_has_occur) < 0))) __PYX_ERR(0, 92, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /* "epanet/epanet2_ec.py":1 - * ERROR_CODE = {} # <<<<<<<<<<<<<< - * - * # EPANET 2 Error Messages -*/ - __pyx_t_2 = __Pyx_PyDict_NewPresized(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_GOTREF(__pyx_t_2); - if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_test, __pyx_t_2) < 0) __PYX_ERR(0, 1, __pyx_L1_error) - __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - - /*--- Wrapped vars code ---*/ - - goto __pyx_L0; - __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - if (__pyx_m) { - if (__pyx_mstate->__pyx_d && stringtab_initialized) { - __Pyx_AddTraceback("init epanet.epanet2_ec", __pyx_clineno, __pyx_lineno, __pyx_filename); - } - #if !CYTHON_USE_MODULE_STATE - Py_CLEAR(__pyx_m); - #else - Py_DECREF(__pyx_m); - if (pystate_addmodule_run) { - PyObject *tp, *value, *tb; - PyErr_Fetch(&tp, &value, &tb); - PyState_RemoveModule(&__pyx_moduledef); - PyErr_Restore(tp, value, tb); - } - #endif - } else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_ImportError, "init epanet.epanet2_ec"); - } - __pyx_L0:; - __Pyx_RefNannyFinishContext(); - #if CYTHON_PEP489_MULTI_PHASE_INIT - return (__pyx_m != NULL) ? 0 : -1; - #else - return __pyx_m; - #endif -} -/* #### Code section: pystring_table ### */ - -typedef struct { - const char *s; -#if 61 <= 65535 - const unsigned short n; -#elif 61 / 2 < INT_MAX - const unsigned int n; -#elif 61 / 2 < LONG_MAX - const unsigned long n; -#else - const Py_ssize_t n; -#endif -#if 1 <= 31 - const unsigned int encoding : 5; -#elif 1 <= 255 - const unsigned char encoding; -#elif 1 <= 65535 - const unsigned short encoding; -#else - const Py_ssize_t encoding; -#endif - const unsigned int is_unicode : 1; - const unsigned int intern : 1; -} __Pyx_StringTabEntry; -static const char * const __pyx_string_tab_encodings[] = { 0 }; -static const __Pyx_StringTabEntry __pyx_string_tab[] = { - {__pyx_k_, sizeof(__pyx_k_), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_ */ - {__pyx_k_0, sizeof(__pyx_k_0), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_0 */ - {__pyx_k_10, sizeof(__pyx_k_10), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_10 */ - {__pyx_k_101, sizeof(__pyx_k_101), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_101 */ - {__pyx_k_102, sizeof(__pyx_k_102), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_102 */ - {__pyx_k_103, sizeof(__pyx_k_103), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_103 */ - {__pyx_k_104, sizeof(__pyx_k_104), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_104 */ - {__pyx_k_105, sizeof(__pyx_k_105), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_105 */ - {__pyx_k_106, sizeof(__pyx_k_106), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_106 */ - {__pyx_k_107, sizeof(__pyx_k_107), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_107 */ - {__pyx_k_108, sizeof(__pyx_k_108), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_108 */ - {__pyx_k_110, sizeof(__pyx_k_110), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_110 */ - {__pyx_k_120, sizeof(__pyx_k_120), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_120 */ - {__pyx_k_200, sizeof(__pyx_k_200), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_200 */ - {__pyx_k_201, sizeof(__pyx_k_201), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_201 */ - {__pyx_k_202, sizeof(__pyx_k_202), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_202 */ - {__pyx_k_203, sizeof(__pyx_k_203), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_203 */ - {__pyx_k_204, sizeof(__pyx_k_204), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_204 */ - {__pyx_k_205, sizeof(__pyx_k_205), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_205 */ - {__pyx_k_206, sizeof(__pyx_k_206), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_206 */ - {__pyx_k_207, sizeof(__pyx_k_207), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_207 */ - {__pyx_k_208, sizeof(__pyx_k_208), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_208 */ - {__pyx_k_209, sizeof(__pyx_k_209), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_209 */ - {__pyx_k_211, sizeof(__pyx_k_211), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_211 */ - {__pyx_k_212, sizeof(__pyx_k_212), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_212 */ - {__pyx_k_213, sizeof(__pyx_k_213), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_213 */ - {__pyx_k_214, sizeof(__pyx_k_214), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_214 */ - {__pyx_k_215, sizeof(__pyx_k_215), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_215 */ - {__pyx_k_216, sizeof(__pyx_k_216), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_216 */ - {__pyx_k_217, sizeof(__pyx_k_217), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_217 */ - {__pyx_k_219, sizeof(__pyx_k_219), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_219 */ - {__pyx_k_220, sizeof(__pyx_k_220), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_220 */ - {__pyx_k_221, sizeof(__pyx_k_221), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_221 */ - {__pyx_k_222, sizeof(__pyx_k_222), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_222 */ - {__pyx_k_223, sizeof(__pyx_k_223), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_223 */ - {__pyx_k_224, sizeof(__pyx_k_224), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_224 */ - {__pyx_k_225, sizeof(__pyx_k_225), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_225 */ - {__pyx_k_226, sizeof(__pyx_k_226), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_226 */ - {__pyx_k_227, sizeof(__pyx_k_227), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_227 */ - {__pyx_k_230, sizeof(__pyx_k_230), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_230 */ - {__pyx_k_233, sizeof(__pyx_k_233), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_233 */ - {__pyx_k_234, sizeof(__pyx_k_234), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_234 */ - {__pyx_k_240, sizeof(__pyx_k_240), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_240 */ - {__pyx_k_241, sizeof(__pyx_k_241), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_241 */ - {__pyx_k_250, sizeof(__pyx_k_250), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_250 */ - {__pyx_k_251, sizeof(__pyx_k_251), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_251 */ - {__pyx_k_252, sizeof(__pyx_k_252), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_252 */ - {__pyx_k_253, sizeof(__pyx_k_253), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_253 */ - {__pyx_k_254, sizeof(__pyx_k_254), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_254 */ - {__pyx_k_255, sizeof(__pyx_k_255), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_255 */ - {__pyx_k_257, sizeof(__pyx_k_257), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_257 */ - {__pyx_k_258, sizeof(__pyx_k_258), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_258 */ - {__pyx_k_259, sizeof(__pyx_k_259), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_259 */ - {__pyx_k_260, sizeof(__pyx_k_260), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_260 */ - {__pyx_k_261, sizeof(__pyx_k_261), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_261 */ - {__pyx_k_262, sizeof(__pyx_k_262), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_262 */ - {__pyx_k_263, sizeof(__pyx_k_263), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_263 */ - {__pyx_k_301, sizeof(__pyx_k_301), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_301 */ - {__pyx_k_302, sizeof(__pyx_k_302), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_302 */ - {__pyx_k_303, sizeof(__pyx_k_303), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_303 */ - {__pyx_k_304, sizeof(__pyx_k_304), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_304 */ - {__pyx_k_305, sizeof(__pyx_k_305), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_305 */ - {__pyx_k_306, sizeof(__pyx_k_306), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_306 */ - {__pyx_k_307, sizeof(__pyx_k_307), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_307 */ - {__pyx_k_308, sizeof(__pyx_k_308), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_308 */ - {__pyx_k_309, sizeof(__pyx_k_309), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_309 */ - {__pyx_k_411, sizeof(__pyx_k_411), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_411 */ - {__pyx_k_412, sizeof(__pyx_k_412), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_412 */ - {__pyx_k_421, sizeof(__pyx_k_421), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_421 */ - {__pyx_k_422, sizeof(__pyx_k_422), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_422 */ - {__pyx_k_423, sizeof(__pyx_k_423), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_423 */ - {__pyx_k_434, sizeof(__pyx_k_434), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_434 */ - {__pyx_k_435, sizeof(__pyx_k_435), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_435 */ - {__pyx_k_436, sizeof(__pyx_k_436), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_436 */ - {__pyx_k_ERR, sizeof(__pyx_k_ERR), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ERR */ - {__pyx_k_ERROR_CODE, sizeof(__pyx_k_ERROR_CODE), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ERROR_CODE */ - {__pyx_k_Error_An_unknown_error_has_occur, sizeof(__pyx_k_Error_An_unknown_error_has_occur), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Error_An_unknown_error_has_occur */ - {__pyx_k_File_Error_434_unable_to_open_bi, sizeof(__pyx_k_File_Error_434_unable_to_open_bi), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_File_Error_434_unable_to_open_bi */ - {__pyx_k_File_Error_435_invalid_binary_fi, sizeof(__pyx_k_File_Error_435_invalid_binary_fi), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_File_Error_435_invalid_binary_fi */ - {__pyx_k_File_Error_436_no_results_in_bin, sizeof(__pyx_k_File_Error_436_no_results_in_bin), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_File_Error_436_no_results_in_bin */ - {__pyx_k_Input_Error_411_no_memory_alloca, sizeof(__pyx_k_Input_Error_411_no_memory_alloca), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Input_Error_411_no_memory_alloca */ - {__pyx_k_Input_Error_412_binary_file_hasn, sizeof(__pyx_k_Input_Error_412_binary_file_hasn), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Input_Error_412_binary_file_hasn */ - {__pyx_k_Input_Error_421_invalid_paramete, sizeof(__pyx_k_Input_Error_421_invalid_paramete), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Input_Error_421_invalid_paramete */ - {__pyx_k_Input_Error_422_reporting_period, sizeof(__pyx_k_Input_Error_422_reporting_period), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Input_Error_422_reporting_period */ - {__pyx_k_Input_Error_423_element_index_ou, sizeof(__pyx_k_Input_Error_423_element_index_ou), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Input_Error_423_element_index_ou */ - {__pyx_k_Warning_model_run_issued_warning, sizeof(__pyx_k_Warning_model_run_issued_warning), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_Warning_model_run_issued_warning */ - {__pyx_k_attempt_to_control_CV_GPV_link, sizeof(__pyx_k_attempt_to_control_CV_GPV_link), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_attempt_to_control_CV_GPV_link */ - {__pyx_k_attempt_to_delete_a_node_or_link, sizeof(__pyx_k_attempt_to_delete_a_node_or_link), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_attempt_to_delete_a_node_or_link */ - {__pyx_k_attempt_to_delete_a_node_that_st, sizeof(__pyx_k_attempt_to_delete_a_node_that_st), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_attempt_to_delete_a_node_that_st */ - {__pyx_k_attempt_to_delete_node_assigned, sizeof(__pyx_k_attempt_to_delete_node_assigned), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_attempt_to_delete_node_assigned */ - {__pyx_k_attempt_to_modify_network_struct, sizeof(__pyx_k_attempt_to_modify_network_struct), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_attempt_to_modify_network_struct */ - {__pyx_k_cannot_open_binary_output_file, sizeof(__pyx_k_cannot_open_binary_output_file), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_open_binary_output_file */ - {__pyx_k_cannot_open_hydraulics_file, sizeof(__pyx_k_cannot_open_hydraulics_file), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_open_hydraulics_file */ - {__pyx_k_cannot_open_input_file, sizeof(__pyx_k_cannot_open_input_file), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_open_input_file */ - {__pyx_k_cannot_open_report_file, sizeof(__pyx_k_cannot_open_report_file), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_open_report_file */ - {__pyx_k_cannot_read_hydraulics_file, sizeof(__pyx_k_cannot_read_hydraulics_file), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_read_hydraulics_file */ - {__pyx_k_cannot_save_results_to_file, sizeof(__pyx_k_cannot_save_results_to_file), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_save_results_to_file */ - {__pyx_k_cannot_save_results_to_report_fi, sizeof(__pyx_k_cannot_save_results_to_report_fi), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_save_results_to_report_fi */ - {__pyx_k_cannot_solve_network_hydraulic_e, sizeof(__pyx_k_cannot_solve_network_hydraulic_e), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_solve_network_hydraulic_e */ - {__pyx_k_cannot_solve_water_quality_trans, sizeof(__pyx_k_cannot_solve_water_quality_trans), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_solve_water_quality_trans */ - {__pyx_k_cannot_use_external_file_while_h, sizeof(__pyx_k_cannot_use_external_file_while_h), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_cannot_use_external_file_while_h */ - {__pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 1, 1}, /* PyObject cname: __pyx_n_u_cline_in_traceback */ - {__pyx_k_duplicate_ID_label, sizeof(__pyx_k_duplicate_ID_label), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_duplicate_ID_label */ - {__pyx_k_hydraulic_solver_not_opened, sizeof(__pyx_k_hydraulic_solver_not_opened), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_hydraulic_solver_not_opened */ - {__pyx_k_hydraulics_file_does_not_match_n, sizeof(__pyx_k_hydraulics_file_does_not_match_n), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_hydraulics_file_does_not_match_n */ - {__pyx_k_hydraulics_supplied_from_externa, sizeof(__pyx_k_hydraulics_supplied_from_externa), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_hydraulics_supplied_from_externa */ - {__pyx_k_identical_file_names, sizeof(__pyx_k_identical_file_names), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_identical_file_names */ - {__pyx_k_illegal_PDA_pressure_limits, sizeof(__pyx_k_illegal_PDA_pressure_limits), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_illegal_PDA_pressure_limits */ - {__pyx_k_illegal_link_property_value, sizeof(__pyx_k_illegal_link_property_value), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_illegal_link_property_value */ - {__pyx_k_illegal_node_property_value, sizeof(__pyx_k_illegal_node_property_value), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_illegal_node_property_value */ - {__pyx_k_illegal_numeric_value, sizeof(__pyx_k_illegal_numeric_value), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_illegal_numeric_value */ - {__pyx_k_illegal_valve_connection_to_anot, sizeof(__pyx_k_illegal_valve_connection_to_anot), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_illegal_valve_connection_to_anot */ - {__pyx_k_illegal_valve_connection_to_tank, sizeof(__pyx_k_illegal_valve_connection_to_tank), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_illegal_valve_connection_to_tank */ - {__pyx_k_insufficient_memory_available, sizeof(__pyx_k_insufficient_memory_available), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_insufficient_memory_available */ - {__pyx_k_invalid_ID_name, sizeof(__pyx_k_invalid_ID_name), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_ID_name */ - {__pyx_k_invalid_format, sizeof(__pyx_k_invalid_format), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_format */ - {__pyx_k_invalid_head_curve_for_pump, sizeof(__pyx_k_invalid_head_curve_for_pump), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_head_curve_for_pump */ - {__pyx_k_invalid_link_vertex, sizeof(__pyx_k_invalid_link_vertex), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_link_vertex */ - {__pyx_k_invalid_lower_upper_levels_for_t, sizeof(__pyx_k_invalid_lower_upper_levels_for_t), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_lower_upper_levels_for_t */ - {__pyx_k_invalid_option_value, sizeof(__pyx_k_invalid_option_value), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_option_value */ - {__pyx_k_invalid_parameter_code, sizeof(__pyx_k_invalid_parameter_code), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_parameter_code */ - {__pyx_k_invalid_pump_energy_data, sizeof(__pyx_k_invalid_pump_energy_data), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_invalid_pump_energy_data */ - {__pyx_k_main, sizeof(__pyx_k_main), 0, 1, 1}, /* PyObject cname: __pyx_n_u_main */ - {__pyx_k_mis_placed_rule_clause_in_rule_b, sizeof(__pyx_k_mis_placed_rule_clause_in_rule_b), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_mis_placed_rule_clause_in_rule_b */ - {__pyx_k_module, sizeof(__pyx_k_module), 0, 1, 1}, /* PyObject cname: __pyx_n_u_module */ - {__pyx_k_name, sizeof(__pyx_k_name), 0, 1, 1}, /* PyObject cname: __pyx_n_u_name */ - {__pyx_k_network_has_an_unconnected_node, sizeof(__pyx_k_network_has_an_unconnected_node), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_network_has_an_unconnected_node */ - {__pyx_k_network_has_unconnected_nodes, sizeof(__pyx_k_network_has_unconnected_nodes), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_network_has_unconnected_nodes */ - {__pyx_k_no_head_curve_or_power_rating_fo, sizeof(__pyx_k_no_head_curve_or_power_rating_fo), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_no_head_curve_or_power_rating_fo */ - {__pyx_k_no_hydraulics_for_water_quality, sizeof(__pyx_k_no_hydraulics_for_water_quality), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_no_hydraulics_for_water_quality */ - {__pyx_k_no_network_data_available, sizeof(__pyx_k_no_network_data_available), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_no_network_data_available */ - {__pyx_k_no_results_saved_to_report_on, sizeof(__pyx_k_no_results_saved_to_report_on), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_no_results_saved_to_report_on */ - {__pyx_k_no_tanks_or_reservoirs_in_networ, sizeof(__pyx_k_no_tanks_or_reservoirs_in_networ), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_no_tanks_or_reservoirs_in_networ */ - {__pyx_k_node_is_not_a_tank, sizeof(__pyx_k_node_is_not_a_tank), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_node_is_not_a_tank */ - {__pyx_k_node_with_no_coordinates, sizeof(__pyx_k_node_with_no_coordinates), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_node_with_no_coordinates */ - {__pyx_k_nonexistent_control, sizeof(__pyx_k_nonexistent_control), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_nonexistent_control */ - {__pyx_k_nonexistent_demand_category, sizeof(__pyx_k_nonexistent_demand_category), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_nonexistent_demand_category */ - {__pyx_k_nonexistent_rule, sizeof(__pyx_k_nonexistent_rule), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_nonexistent_rule */ - {__pyx_k_nonexistent_rule_clause, sizeof(__pyx_k_nonexistent_rule_clause), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_nonexistent_rule_clause */ - {__pyx_k_nonexistent_source, sizeof(__pyx_k_nonexistent_source), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_nonexistent_source */ - {__pyx_k_nonincreasing_x_values_for_curve, sizeof(__pyx_k_nonincreasing_x_values_for_curve), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_nonincreasing_x_values_for_curve */ - {__pyx_k_not_enough_nodes_in_network, sizeof(__pyx_k_not_enough_nodes_in_network), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_not_enough_nodes_in_network */ - {__pyx_k_ok, sizeof(__pyx_k_ok), 0, 1, 1}, /* PyObject cname: __pyx_n_u_ok */ - {__pyx_k_one_or_more_errors_in_input_file, sizeof(__pyx_k_one_or_more_errors_in_input_file), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_one_or_more_errors_in_input_file */ - {__pyx_k_qualname, sizeof(__pyx_k_qualname), 0, 1, 1}, /* PyObject cname: __pyx_n_u_qualname */ - {__pyx_k_reference_to_undefined_pump, sizeof(__pyx_k_reference_to_undefined_pump), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_reference_to_undefined_pump */ - {__pyx_k_same_start_and_end_nodes_for_lin, sizeof(__pyx_k_same_start_and_end_nodes_for_lin), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_same_start_and_end_nodes_for_lin */ - {__pyx_k_syntax_error, sizeof(__pyx_k_syntax_error), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_syntax_error */ - {__pyx_k_test, sizeof(__pyx_k_test), 0, 1, 1}, /* PyObject cname: __pyx_n_u_test */ - {__pyx_k_too_many_characters_in_input_lin, sizeof(__pyx_k_too_many_characters_in_input_lin), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_too_many_characters_in_input_lin */ - {__pyx_k_undefined_curve, sizeof(__pyx_k_undefined_curve), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_undefined_curve */ - {__pyx_k_undefined_link, sizeof(__pyx_k_undefined_link), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_undefined_link */ - {__pyx_k_undefined_node, sizeof(__pyx_k_undefined_node), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_undefined_node */ - {__pyx_k_undefined_time_pattern, sizeof(__pyx_k_undefined_time_pattern), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_undefined_time_pattern */ - {__pyx_k_undefined_trace_node, sizeof(__pyx_k_undefined_trace_node), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_undefined_trace_node */ - {__pyx_k_water_quality_solver_not_opened, sizeof(__pyx_k_water_quality_solver_not_opened), 0, 1, 0}, /* PyObject cname: __pyx_kp_u_water_quality_solver_not_opened */ - {0, 0, 0, 0, 0} -}; -/* InitStrings.proto */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry const *t, PyObject **target, const char* const* encoding_names); - -/* #### Code section: cached_builtins ### */ - -static int __Pyx_InitCachedBuiltins(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - return 0; -} -/* #### Code section: cached_constants ### */ - -static int __Pyx_InitCachedConstants(__pyx_mstatetype *__pyx_mstate) { - __Pyx_RefNannyDeclarations - CYTHON_UNUSED_VAR(__pyx_mstate); - __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); - __Pyx_RefNannyFinishContext(); - return 0; -} -/* #### Code section: init_constants ### */ - -static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - if (__Pyx_InitStrings(__pyx_string_tab, __pyx_mstate->__pyx_string_tab, __pyx_string_tab_encodings) < 0) __PYX_ERR(0, 1, __pyx_L1_error); - return 0; - __pyx_L1_error:; - return -1; -} -/* #### Code section: init_codeobjects ### */ - -static int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate) { - CYTHON_UNUSED_VAR(__pyx_mstate); - return 0; -} -/* #### Code section: init_globals ### */ - -static int __Pyx_InitGlobals(void) { - /* PythonCompatibility.init */ - if (likely(__Pyx_init_co_variables() == 0)); else - -if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 1, __pyx_L1_error) - - return 0; - __pyx_L1_error:; - return -1; -} -/* #### Code section: cleanup_globals ### */ -/* #### Code section: cleanup_module ### */ -/* #### Code section: main_method ### */ -/* #### Code section: utility_code_pragmas ### */ -#ifdef _MSC_VER -#pragma warning( push ) -/* Warning 4127: conditional expression is constant - * Cython uses constant conditional expressions to allow in inline functions to be optimized at - * compile-time, so this warning is not useful - */ -#pragma warning( disable : 4127 ) -#endif - - - -/* #### Code section: utility_code_def ### */ - -/* --- Runtime support code --- */ -/* Refnanny */ -#if CYTHON_REFNANNY -static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule(modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, "RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); -end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; -} -#endif - -/* PyErrExceptionMatches */ -#if CYTHON_FAST_THREAD_STATE -static int __Pyx_PyErr_ExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(tuple); - for (i=0; i= 0x030C00A6 - PyObject *current_exception = tstate->current_exception; - if (unlikely(!current_exception)) return 0; - exc_type = (PyObject*) Py_TYPE(current_exception); - if (exc_type == err) return 1; -#else - exc_type = tstate->curexc_type; - if (exc_type == err) return 1; - if (unlikely(!exc_type)) return 0; -#endif - #if CYTHON_AVOID_BORROWED_REFS - Py_INCREF(exc_type); - #endif - if (unlikely(PyTuple_Check(err))) { - result = __Pyx_PyErr_ExceptionMatchesTuple(exc_type, err); - } else { - result = __Pyx_PyErr_GivenExceptionMatches(exc_type, err); - } - #if CYTHON_AVOID_BORROWED_REFS - Py_DECREF(exc_type); - #endif - return result; -} -#endif - -/* PyErrFetchRestore */ -#if CYTHON_FAST_THREAD_STATE -static CYTHON_INLINE void __Pyx_ErrRestoreInState(PyThreadState *tstate, PyObject *type, PyObject *value, PyObject *tb) { -#if PY_VERSION_HEX >= 0x030C00A6 - PyObject *tmp_value; - assert(type == NULL || (value != NULL && type == (PyObject*) Py_TYPE(value))); - if (value) { - #if CYTHON_COMPILING_IN_CPYTHON - if (unlikely(((PyBaseExceptionObject*) value)->traceback != tb)) - #endif - PyException_SetTraceback(value, tb); - } - tmp_value = tstate->current_exception; - tstate->current_exception = value; - Py_XDECREF(tmp_value); - Py_XDECREF(type); - Py_XDECREF(tb); -#else - PyObject *tmp_type, *tmp_value, *tmp_tb; - tmp_type = tstate->curexc_type; - tmp_value = tstate->curexc_value; - tmp_tb = tstate->curexc_traceback; - tstate->curexc_type = type; - tstate->curexc_value = value; - tstate->curexc_traceback = tb; - Py_XDECREF(tmp_type); - Py_XDECREF(tmp_value); - Py_XDECREF(tmp_tb); -#endif -} -static CYTHON_INLINE void __Pyx_ErrFetchInState(PyThreadState *tstate, PyObject **type, PyObject **value, PyObject **tb) { -#if PY_VERSION_HEX >= 0x030C00A6 - PyObject* exc_value; - exc_value = tstate->current_exception; - tstate->current_exception = 0; - *value = exc_value; - *type = NULL; - *tb = NULL; - if (exc_value) { - *type = (PyObject*) Py_TYPE(exc_value); - Py_INCREF(*type); - #if CYTHON_COMPILING_IN_CPYTHON - *tb = ((PyBaseExceptionObject*) exc_value)->traceback; - Py_XINCREF(*tb); - #else - *tb = PyException_GetTraceback(exc_value); - #endif - } -#else - *type = tstate->curexc_type; - *value = tstate->curexc_value; - *tb = tstate->curexc_traceback; - tstate->curexc_type = 0; - tstate->curexc_value = 0; - tstate->curexc_traceback = 0; -#endif -} -#endif - -/* PyObjectGetAttrStr */ -#if CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_getattro)) - return tp->tp_getattro(obj, attr_name); - return PyObject_GetAttr(obj, attr_name); -} -#endif - -/* PyObjectGetAttrStrNoError */ -#if __PYX_LIMITED_VERSION_HEX < 0x030d0000 -static void __Pyx_PyObject_GetAttrStr_ClearAttributeError(void) { - __Pyx_PyThreadState_declare - __Pyx_PyThreadState_assign - if (likely(__Pyx_PyErr_ExceptionMatches(PyExc_AttributeError))) - __Pyx_PyErr_Clear(); -} -#endif -static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStrNoError(PyObject* obj, PyObject* attr_name) { - PyObject *result; -#if __PYX_LIMITED_VERSION_HEX >= 0x030d0000 - (void) PyObject_GetOptionalAttr(obj, attr_name, &result); - return result; -#else -#if CYTHON_COMPILING_IN_CPYTHON && CYTHON_USE_TYPE_SLOTS - PyTypeObject* tp = Py_TYPE(obj); - if (likely(tp->tp_getattro == PyObject_GenericGetAttr)) { - return _PyObject_GenericGetAttrWithDict(obj, attr_name, NULL, 1); - } -#endif - result = __Pyx_PyObject_GetAttrStr(obj, attr_name); - if (unlikely(!result)) { - __Pyx_PyObject_GetAttrStr_ClearAttributeError(); - } - return result; -#endif -} - -/* GetBuiltinName */ -static PyObject *__Pyx_GetBuiltinName(PyObject *name) { - PyObject* result = __Pyx_PyObject_GetAttrStrNoError(__pyx_mstate_global->__pyx_b, name); - if (unlikely(!result) && !PyErr_Occurred()) { - PyErr_Format(PyExc_NameError, - "name '%U' is not defined", name); - } - return result; -} - -/* PyDictVersioning */ -#if CYTHON_USE_DICT_VERSIONS && CYTHON_USE_TYPE_SLOTS -static CYTHON_INLINE PY_UINT64_T __Pyx_get_tp_dict_version(PyObject *obj) { - PyObject *dict = Py_TYPE(obj)->tp_dict; - return likely(dict) ? __PYX_GET_DICT_VERSION(dict) : 0; -} -static CYTHON_INLINE PY_UINT64_T __Pyx_get_object_dict_version(PyObject *obj) { - PyObject **dictptr = NULL; - Py_ssize_t offset = Py_TYPE(obj)->tp_dictoffset; - if (offset) { -#if CYTHON_COMPILING_IN_CPYTHON - dictptr = (likely(offset > 0)) ? (PyObject **) ((char *)obj + offset) : _PyObject_GetDictPtr(obj); -#else - dictptr = _PyObject_GetDictPtr(obj); -#endif - } - return (dictptr && *dictptr) ? __PYX_GET_DICT_VERSION(*dictptr) : 0; -} -static CYTHON_INLINE int __Pyx_object_dict_version_matches(PyObject* obj, PY_UINT64_T tp_dict_version, PY_UINT64_T obj_dict_version) { - PyObject *dict = Py_TYPE(obj)->tp_dict; - if (unlikely(!dict) || unlikely(tp_dict_version != __PYX_GET_DICT_VERSION(dict))) - return 0; - return obj_dict_version == __Pyx_get_object_dict_version(obj); -} -#endif - -/* GetModuleGlobalName */ -#if CYTHON_USE_DICT_VERSIONS -static PyObject *__Pyx__GetModuleGlobalName(PyObject *name, PY_UINT64_T *dict_version, PyObject **dict_cached_value) -#else -static CYTHON_INLINE PyObject *__Pyx__GetModuleGlobalName(PyObject *name) -#endif -{ - PyObject *result; -#if CYTHON_COMPILING_IN_LIMITED_API - if (unlikely(!__pyx_m)) { - if (!PyErr_Occurred()) - PyErr_SetNone(PyExc_NameError); - return NULL; - } - result = PyObject_GetAttr(__pyx_m, name); - if (likely(result)) { - return result; - } - PyErr_Clear(); -#elif CYTHON_AVOID_BORROWED_REFS || CYTHON_AVOID_THREAD_UNSAFE_BORROWED_REFS - if (unlikely(__Pyx_PyDict_GetItemRef(__pyx_mstate_global->__pyx_d, name, &result) == -1)) PyErr_Clear(); - __PYX_UPDATE_DICT_CACHE(__pyx_mstate_global->__pyx_d, result, *dict_cached_value, *dict_version) - if (likely(result)) { - return result; - } -#else - result = _PyDict_GetItem_KnownHash(__pyx_mstate_global->__pyx_d, name, ((PyASCIIObject *) name)->hash); - __PYX_UPDATE_DICT_CACHE(__pyx_mstate_global->__pyx_d, result, *dict_cached_value, *dict_version) - if (likely(result)) { - return __Pyx_NewRef(result); - } - PyErr_Clear(); -#endif - return __Pyx_GetBuiltinName(name); -} - -/* CLineInTraceback */ -#if CYTHON_CLINE_IN_TRACEBACK && CYTHON_CLINE_IN_TRACEBACK_RUNTIME -static int __Pyx_CLineForTraceback(PyThreadState *tstate, int c_line) { - PyObject *use_cline; - PyObject *ptype, *pvalue, *ptraceback; -#if CYTHON_COMPILING_IN_CPYTHON - PyObject **cython_runtime_dict; -#endif - CYTHON_MAYBE_UNUSED_VAR(tstate); - if (unlikely(!__pyx_mstate_global->__pyx_cython_runtime)) { - return c_line; - } - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); -#if CYTHON_COMPILING_IN_CPYTHON - cython_runtime_dict = _PyObject_GetDictPtr(__pyx_mstate_global->__pyx_cython_runtime); - if (likely(cython_runtime_dict)) { - __Pyx_BEGIN_CRITICAL_SECTION(*cython_runtime_dict); - __PYX_PY_DICT_LOOKUP_IF_MODIFIED( - use_cline, *cython_runtime_dict, - __Pyx_PyDict_GetItemStr(*cython_runtime_dict, __pyx_mstate_global->__pyx_n_u_cline_in_traceback)) - Py_XINCREF(use_cline); - __Pyx_END_CRITICAL_SECTION(); - } else -#endif - { - PyObject *use_cline_obj = __Pyx_PyObject_GetAttrStrNoError(__pyx_mstate_global->__pyx_cython_runtime, __pyx_mstate_global->__pyx_n_u_cline_in_traceback); - if (use_cline_obj) { - use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True; - Py_INCREF(use_cline); - Py_DECREF(use_cline_obj); - } else { - PyErr_Clear(); - use_cline = NULL; - } - } - if (!use_cline) { - c_line = 0; - (void) PyObject_SetAttr(__pyx_mstate_global->__pyx_cython_runtime, __pyx_mstate_global->__pyx_n_u_cline_in_traceback, Py_False); - } - else if (use_cline == Py_False || (use_cline != Py_True && PyObject_Not(use_cline) != 0)) { - c_line = 0; - } - Py_XDECREF(use_cline); - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - return c_line; -} -#endif - -/* CodeObjectCache */ -static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { - int start = 0, mid = 0, end = count - 1; - if (end >= 0 && code_line > entries[end].code_line) { - return count; - } - while (start < end) { - mid = start + (end - start) / 2; - if (code_line < entries[mid].code_line) { - end = mid; - } else if (code_line > entries[mid].code_line) { - start = mid + 1; - } else { - return mid; - } - } - if (code_line <= entries[mid].code_line) { - return mid; - } else { - return mid + 1; - } -} -static __Pyx_CachedCodeObjectType *__pyx__find_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line) { - __Pyx_CachedCodeObjectType* code_object; - int pos; - if (unlikely(!code_line) || unlikely(!code_cache->entries)) { - return NULL; - } - pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); - if (unlikely(pos >= code_cache->count) || unlikely(code_cache->entries[pos].code_line != code_line)) { - return NULL; - } - code_object = code_cache->entries[pos].code_object; - Py_INCREF(code_object); - return code_object; -} -static __Pyx_CachedCodeObjectType *__pyx_find_code_object(int code_line) { -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS - (void)__pyx__find_code_object; - return NULL; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just miss. -#else - struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_nonatomic_int_type old_count = __pyx_atomic_incr_acq_rel(&code_cache->accessor_count); - if (old_count < 0) { - __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); - return NULL; - } -#endif - __Pyx_CachedCodeObjectType *result = __pyx__find_code_object(code_cache, code_line); -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_decr_acq_rel(&code_cache->accessor_count); -#endif - return result; -#endif -} -static void __pyx__insert_code_object(struct __Pyx_CodeObjectCache *code_cache, int code_line, __Pyx_CachedCodeObjectType* code_object) -{ - int pos, i; - __Pyx_CodeObjectCacheEntry* entries = code_cache->entries; - if (unlikely(!code_line)) { - return; - } - if (unlikely(!entries)) { - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); - if (likely(entries)) { - code_cache->entries = entries; - code_cache->max_count = 64; - code_cache->count = 1; - entries[0].code_line = code_line; - entries[0].code_object = code_object; - Py_INCREF(code_object); - } - return; - } - pos = __pyx_bisect_code_objects(code_cache->entries, code_cache->count, code_line); - if ((pos < code_cache->count) && unlikely(code_cache->entries[pos].code_line == code_line)) { - __Pyx_CachedCodeObjectType* tmp = entries[pos].code_object; - entries[pos].code_object = code_object; - Py_INCREF(code_object); - Py_DECREF(tmp); - return; - } - if (code_cache->count == code_cache->max_count) { - int new_max = code_cache->max_count + 64; - entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( - code_cache->entries, ((size_t)new_max) * sizeof(__Pyx_CodeObjectCacheEntry)); - if (unlikely(!entries)) { - return; - } - code_cache->entries = entries; - code_cache->max_count = new_max; - } - for (i=code_cache->count; i>pos; i--) { - entries[i] = entries[i-1]; - } - entries[pos].code_line = code_line; - entries[pos].code_object = code_object; - code_cache->count++; - Py_INCREF(code_object); -} -static void __pyx_insert_code_object(int code_line, __Pyx_CachedCodeObjectType* code_object) { -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING && !CYTHON_ATOMICS - (void)__pyx__insert_code_object; - return; // Most implementation should have atomics. But otherwise, don't make it thread-safe, just fail. -#else - struct __Pyx_CodeObjectCache *code_cache = &__pyx_mstate_global->__pyx_code_cache; -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_nonatomic_int_type expected = 0; - if (!__pyx_atomic_int_cmp_exchange(&code_cache->accessor_count, &expected, INT_MIN)) { - return; - } -#endif - __pyx__insert_code_object(code_cache, code_line, code_object); -#if CYTHON_COMPILING_IN_CPYTHON_FREETHREADING - __pyx_atomic_sub(&code_cache->accessor_count, INT_MIN); -#endif -#endif -} - -/* AddTraceback */ -#include "compile.h" -#include "frameobject.h" -#include "traceback.h" -#if PY_VERSION_HEX >= 0x030b00a6 && !CYTHON_COMPILING_IN_LIMITED_API && !defined(PYPY_VERSION) - #ifndef Py_BUILD_CORE - #define Py_BUILD_CORE 1 - #endif - #include "internal/pycore_frame.h" -#endif -#if CYTHON_COMPILING_IN_LIMITED_API -static PyObject *__Pyx_PyCode_Replace_For_AddTraceback(PyObject *code, PyObject *scratch_dict, - PyObject *firstlineno, PyObject *name) { - PyObject *replace = NULL; - if (unlikely(PyDict_SetItemString(scratch_dict, "co_firstlineno", firstlineno))) return NULL; - if (unlikely(PyDict_SetItemString(scratch_dict, "co_name", name))) return NULL; - replace = PyObject_GetAttrString(code, "replace"); - if (likely(replace)) { - PyObject *result = PyObject_Call(replace, __pyx_mstate_global->__pyx_empty_tuple, scratch_dict); - Py_DECREF(replace); - return result; - } - PyErr_Clear(); - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyObject *code_object = NULL, *py_py_line = NULL, *py_funcname = NULL, *dict = NULL; - PyObject *replace = NULL, *getframe = NULL, *frame = NULL; - PyObject *exc_type, *exc_value, *exc_traceback; - int success = 0; - if (c_line) { - (void) __pyx_cfilenm; - (void) __Pyx_CLineForTraceback(__Pyx_PyThreadState_Current, c_line); - } - PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); - code_object = __pyx_find_code_object(c_line ? -c_line : py_line); - if (!code_object) { - code_object = Py_CompileString("_getframe()", filename, Py_eval_input); - if (unlikely(!code_object)) goto bad; - py_py_line = PyLong_FromLong(py_line); - if (unlikely(!py_py_line)) goto bad; - py_funcname = PyUnicode_FromString(funcname); - if (unlikely(!py_funcname)) goto bad; - dict = PyDict_New(); - if (unlikely(!dict)) goto bad; - { - PyObject *old_code_object = code_object; - code_object = __Pyx_PyCode_Replace_For_AddTraceback(code_object, dict, py_py_line, py_funcname); - Py_DECREF(old_code_object); - } - if (unlikely(!code_object)) goto bad; - __pyx_insert_code_object(c_line ? -c_line : py_line, code_object); - } else { - dict = PyDict_New(); - } - getframe = PySys_GetObject("_getframe"); - if (unlikely(!getframe)) goto bad; - if (unlikely(PyDict_SetItemString(dict, "_getframe", getframe))) goto bad; - frame = PyEval_EvalCode(code_object, dict, dict); - if (unlikely(!frame) || frame == Py_None) goto bad; - success = 1; - bad: - PyErr_Restore(exc_type, exc_value, exc_traceback); - Py_XDECREF(code_object); - Py_XDECREF(py_py_line); - Py_XDECREF(py_funcname); - Py_XDECREF(dict); - Py_XDECREF(replace); - if (success) { - PyTraceBack_Here( - (struct _frame*)frame); - } - Py_XDECREF(frame); -} -#else -static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( - const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = NULL; - PyObject *py_funcname = NULL; - if (c_line) { - py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); - if (!py_funcname) goto bad; - funcname = PyUnicode_AsUTF8(py_funcname); - if (!funcname) goto bad; - } - py_code = PyCode_NewEmpty(filename, funcname, py_line); - Py_XDECREF(py_funcname); - return py_code; -bad: - Py_XDECREF(py_funcname); - return NULL; -} -static void __Pyx_AddTraceback(const char *funcname, int c_line, - int py_line, const char *filename) { - PyCodeObject *py_code = 0; - PyFrameObject *py_frame = 0; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject *ptype, *pvalue, *ptraceback; - if (c_line) { - c_line = __Pyx_CLineForTraceback(tstate, c_line); - } - py_code = __pyx_find_code_object(c_line ? -c_line : py_line); - if (!py_code) { - __Pyx_ErrFetchInState(tstate, &ptype, &pvalue, &ptraceback); - py_code = __Pyx_CreateCodeObjectForTraceback( - funcname, c_line, py_line, filename); - if (!py_code) { - /* If the code object creation fails, then we should clear the - fetched exception references and propagate the new exception */ - Py_XDECREF(ptype); - Py_XDECREF(pvalue); - Py_XDECREF(ptraceback); - goto bad; - } - __Pyx_ErrRestoreInState(tstate, ptype, pvalue, ptraceback); - __pyx_insert_code_object(c_line ? -c_line : py_line, py_code); - } - py_frame = PyFrame_New( - tstate, /*PyThreadState *tstate,*/ - py_code, /*PyCodeObject *code,*/ - __pyx_mstate_global->__pyx_d, /*PyObject *globals,*/ - 0 /*PyObject *locals*/ - ); - if (!py_frame) goto bad; - __Pyx_PyFrame_SetLineNumber(py_frame, py_line); - PyTraceBack_Here(py_frame); -bad: - Py_XDECREF(py_code); - Py_XDECREF(py_frame); -} -#endif - -/* FormatTypeName */ -#if CYTHON_COMPILING_IN_LIMITED_API && __PYX_LIMITED_VERSION_HEX < 0x030d0000 -static __Pyx_TypeName -__Pyx_PyType_GetFullyQualifiedName(PyTypeObject* tp) -{ - PyObject *module = NULL, *name = NULL, *result = NULL; - #if __PYX_LIMITED_VERSION_HEX < 0x030b0000 - name = __Pyx_PyObject_GetAttrStr((PyObject *)tp, - __pyx_mstate_global->__pyx_n_u_qualname); - #else - name = PyType_GetQualName(tp); - #endif - if (unlikely(name == NULL) || unlikely(!PyUnicode_Check(name))) goto bad; - module = __Pyx_PyObject_GetAttrStr((PyObject *)tp, - __pyx_mstate_global->__pyx_n_u_module); - if (unlikely(module == NULL) || unlikely(!PyUnicode_Check(module))) goto bad; - if (PyUnicode_CompareWithASCIIString(module, "builtins") == 0) { - result = name; - name = NULL; - goto done; - } - result = PyUnicode_FromFormat("%U.%U", module, name); - if (unlikely(result == NULL)) goto bad; - done: - Py_XDECREF(name); - Py_XDECREF(module); - return result; - bad: - PyErr_Clear(); - if (name) { - result = name; - name = NULL; - } else { - result = __Pyx_NewRef(__pyx_mstate_global->__pyx_kp_u_); - } - goto done; -} -#endif - -/* PyFunctionFastCall */ -#if CYTHON_FAST_PYCALL && !CYTHON_VECTORCALL -static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject *const *args, Py_ssize_t na, - PyObject *globals) { - PyFrameObject *f; - PyThreadState *tstate = __Pyx_PyThreadState_Current; - PyObject **fastlocals; - Py_ssize_t i; - PyObject *result; - assert(globals != NULL); - /* XXX Perhaps we should create a specialized - PyFrame_New() that doesn't take locals, but does - take builtins without sanity checking them. - */ - assert(tstate != NULL); - f = PyFrame_New(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - fastlocals = __Pyx_PyFrame_GetLocalsplus(f); - for (i = 0; i < na; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - result = PyEval_EvalFrameEx(f,0); - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - return result; -} -static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs) { - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *closure; - PyObject *kwdefs; - PyObject *kwtuple, **k; - PyObject **d; - Py_ssize_t nd; - Py_ssize_t nk; - PyObject *result; - assert(kwargs == NULL || PyDict_Check(kwargs)); - nk = kwargs ? PyDict_Size(kwargs) : 0; - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) { - return NULL; - } - if ( - co->co_kwonlyargcount == 0 && - likely(kwargs == NULL || nk == 0) && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { - if (argdefs == NULL && co->co_argcount == nargs) { - result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); - goto done; - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - args = &PyTuple_GET_ITEM(argdefs, 0); - result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); - goto done; - } - } - if (kwargs != NULL) { - Py_ssize_t pos, i; - kwtuple = PyTuple_New(2 * nk); - if (kwtuple == NULL) { - result = NULL; - goto done; - } - k = &PyTuple_GET_ITEM(kwtuple, 0); - pos = i = 0; - while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { - Py_INCREF(k[i]); - Py_INCREF(k[i+1]); - i += 2; - } - nk = i / 2; - } - else { - kwtuple = NULL; - k = NULL; - } - closure = PyFunction_GET_CLOSURE(func); - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, - args, (int)nargs, - k, (int)nk, - d, (int)nd, kwdefs, closure); - Py_XDECREF(kwtuple); -done: - Py_LeaveRecursiveCall(); - return result; -} -#endif - -/* PyObjectCall */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { - PyObject *result; - ternaryfunc call = Py_TYPE(func)->tp_call; - if (unlikely(!call)) - return PyObject_Call(func, arg, kw); - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) - return NULL; - result = (*call)(func, arg, kw); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* PyObjectCallMethO */ -#if CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE PyObject* __Pyx_PyObject_CallMethO(PyObject *func, PyObject *arg) { - PyObject *self, *result; - PyCFunction cfunc; - cfunc = __Pyx_CyOrPyCFunction_GET_FUNCTION(func); - self = __Pyx_CyOrPyCFunction_GET_SELF(func); - if (unlikely(Py_EnterRecursiveCall(" while calling a Python object"))) - return NULL; - result = cfunc(self, arg); - Py_LeaveRecursiveCall(); - if (unlikely(!result) && unlikely(!PyErr_Occurred())) { - PyErr_SetString( - PyExc_SystemError, - "NULL result without error in PyObject_Call"); - } - return result; -} -#endif - -/* PyObjectFastCall */ -#if PY_VERSION_HEX < 0x03090000 || CYTHON_COMPILING_IN_LIMITED_API -static PyObject* __Pyx_PyObject_FastCall_fallback(PyObject *func, PyObject * const*args, size_t nargs, PyObject *kwargs) { - PyObject *argstuple; - PyObject *result = 0; - size_t i; - argstuple = PyTuple_New((Py_ssize_t)nargs); - if (unlikely(!argstuple)) return NULL; - for (i = 0; i < nargs; i++) { - Py_INCREF(args[i]); - if (__Pyx_PyTuple_SET_ITEM(argstuple, (Py_ssize_t)i, args[i]) != (0)) goto bad; - } - result = __Pyx_PyObject_Call(func, argstuple, kwargs); - bad: - Py_DECREF(argstuple); - return result; -} -#endif -#if CYTHON_VECTORCALL && !CYTHON_COMPILING_IN_LIMITED_API - #if PY_VERSION_HEX < 0x03090000 - #define __Pyx_PyVectorcall_Function(callable) _PyVectorcall_Function(callable) - #elif CYTHON_COMPILING_IN_CPYTHON -static CYTHON_INLINE vectorcallfunc __Pyx_PyVectorcall_Function(PyObject *callable) { - PyTypeObject *tp = Py_TYPE(callable); - #if defined(__Pyx_CyFunction_USED) - if (__Pyx_CyFunction_CheckExact(callable)) { - return __Pyx_CyFunction_func_vectorcall(callable); - } - #endif - if (!PyType_HasFeature(tp, Py_TPFLAGS_HAVE_VECTORCALL)) { - return NULL; - } - assert(PyCallable_Check(callable)); - Py_ssize_t offset = tp->tp_vectorcall_offset; - assert(offset > 0); - vectorcallfunc ptr; - memcpy(&ptr, (char *) callable + offset, sizeof(ptr)); - return ptr; -} - #else - #define __Pyx_PyVectorcall_Function(callable) PyVectorcall_Function(callable) - #endif -#endif -static CYTHON_INLINE PyObject* __Pyx_PyObject_FastCallDict(PyObject *func, PyObject *const *args, size_t _nargs, PyObject *kwargs) { - Py_ssize_t nargs = __Pyx_PyVectorcall_NARGS(_nargs); -#if CYTHON_COMPILING_IN_CPYTHON - if (nargs == 0 && kwargs == NULL) { - if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_NOARGS)) - return __Pyx_PyObject_CallMethO(func, NULL); - } - else if (nargs == 1 && kwargs == NULL) { - if (__Pyx_CyOrPyCFunction_Check(func) && likely( __Pyx_CyOrPyCFunction_GET_FLAGS(func) & METH_O)) - return __Pyx_PyObject_CallMethO(func, args[0]); - } -#endif - #if PY_VERSION_HEX < 0x030800B1 - #if CYTHON_FAST_PYCCALL - if (PyCFunction_Check(func)) { - if (kwargs) { - return _PyCFunction_FastCallDict(func, args, nargs, kwargs); - } else { - return _PyCFunction_FastCallKeywords(func, args, nargs, NULL); - } - } - if (!kwargs && __Pyx_IS_TYPE(func, &PyMethodDescr_Type)) { - return _PyMethodDescr_FastCallKeywords(func, args, nargs, NULL); - } - #endif - #if CYTHON_FAST_PYCALL - if (PyFunction_Check(func)) { - return __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs); - } - #endif - #endif - if (kwargs == NULL) { - #if CYTHON_VECTORCALL && !CYTHON_COMPILING_IN_LIMITED_API - vectorcallfunc f = __Pyx_PyVectorcall_Function(func); - if (f) { - return f(func, args, _nargs, NULL); - } - #elif defined(__Pyx_CyFunction_USED) && CYTHON_BACKPORT_VECTORCALL - if (__Pyx_CyFunction_CheckExact(func)) { - __pyx_vectorcallfunc f = __Pyx_CyFunction_func_vectorcall(func); - if (f) return f(func, args, _nargs, NULL); - } - #elif CYTHON_COMPILING_IN_LIMITED_API && CYTHON_VECTORCALL - return PyObject_Vectorcall(func, args, _nargs, NULL); - #endif - } - if (nargs == 0) { - return __Pyx_PyObject_Call(func, __pyx_mstate_global->__pyx_empty_tuple, kwargs); - } - #if PY_VERSION_HEX >= 0x03090000 && !CYTHON_COMPILING_IN_LIMITED_API - return PyObject_VectorcallDict(func, args, (size_t)nargs, kwargs); - #else - return __Pyx_PyObject_FastCall_fallback(func, args, (size_t)nargs, kwargs); - #endif -} - -/* PyObjectVectorCallKwBuilder */ -#if CYTHON_VECTORCALL -static int __Pyx_VectorcallBuilder_AddArg(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - (void)__Pyx_PyObject_FastCallDict; - if (__Pyx_PyTuple_SET_ITEM(builder, n, key) != (0)) return -1; - Py_INCREF(key); - args[n] = value; - return 0; -} -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - (void)__Pyx_VectorcallBuilder_AddArgStr; - if (unlikely(!PyUnicode_Check(key))) { - PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return -1; - } - return __Pyx_VectorcallBuilder_AddArg(key, value, builder, args, n); -} -static int __Pyx_VectorcallBuilder_AddArgStr(const char *key, PyObject *value, PyObject *builder, PyObject **args, int n) { - PyObject *pyKey = PyUnicode_FromString(key); - if (!pyKey) return -1; - return __Pyx_VectorcallBuilder_AddArg(pyKey, value, builder, args, n); -} -#else // CYTHON_VECTORCALL -CYTHON_UNUSED static int __Pyx_VectorcallBuilder_AddArg_Check(PyObject *key, PyObject *value, PyObject *builder, CYTHON_UNUSED PyObject **args, CYTHON_UNUSED int n) { - if (unlikely(!PyUnicode_Check(key))) { - PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return -1; - } - return PyDict_SetItem(builder, key, value); -} -#endif - -/* CIntToPy */ -static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (is_unsigned) { - if (sizeof(long) < sizeof(long)) { - return PyLong_FromLong((long) value); - } else if (sizeof(long) <= sizeof(unsigned long)) { - return PyLong_FromUnsignedLong((unsigned long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { - return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); -#endif - } - } else { - if (sizeof(long) <= sizeof(long)) { - return PyLong_FromLong((long) value); -#ifdef HAVE_LONG_LONG - } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { - return PyLong_FromLongLong((PY_LONG_LONG) value); -#endif - } - } - { - unsigned char *bytes = (unsigned char *)&value; -#if !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d00A4 - if (is_unsigned) { - return PyLong_FromUnsignedNativeBytes(bytes, sizeof(value), -1); - } else { - return PyLong_FromNativeBytes(bytes, sizeof(value), -1); - } -#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX < 0x030d0000 - int one = 1; int little = (int)*(unsigned char *)&one; - return _PyLong_FromByteArray(bytes, sizeof(long), - little, !is_unsigned); -#else - int one = 1; int little = (int)*(unsigned char *)&one; - PyObject *from_bytes, *result = NULL, *kwds = NULL; - PyObject *py_bytes = NULL, *order_str = NULL; - from_bytes = PyObject_GetAttrString((PyObject*)&PyLong_Type, "from_bytes"); - if (!from_bytes) return NULL; - py_bytes = PyBytes_FromStringAndSize((char*)bytes, sizeof(long)); - if (!py_bytes) goto limited_bad; - order_str = PyUnicode_FromString(little ? "little" : "big"); - if (!order_str) goto limited_bad; - { - PyObject *args[3+(CYTHON_VECTORCALL ? 1 : 0)] = { NULL, py_bytes, order_str }; - if (!is_unsigned) { - kwds = __Pyx_MakeVectorcallBuilderKwds(1); - if (!kwds) goto limited_bad; - if (__Pyx_VectorcallBuilder_AddArgStr("signed", __Pyx_NewRef(Py_True), kwds, args+3, 0) < 0) goto limited_bad; - } - result = __Pyx_Object_Vectorcall_CallFromBuilder(from_bytes, args+1, 2 | __Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET, kwds); - } - limited_bad: - Py_XDECREF(kwds); - Py_XDECREF(order_str); - Py_XDECREF(py_bytes); - Py_XDECREF(from_bytes); - return result; -#endif - } -} - -/* CIntFromPyVerify */ -#define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) -#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ - __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) -#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ - {\ - func_type value = func_value;\ - if (sizeof(target_type) < sizeof(func_type)) {\ - if (unlikely(value != (func_type) (target_type) value)) {\ - func_type zero = 0;\ - if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ - return (target_type) -1;\ - if (is_unsigned && unlikely(value < zero))\ - goto raise_neg_overflow;\ - else\ - goto raise_overflow;\ - }\ - }\ - return (target_type) value;\ - } - -/* CIntFromPy */ -static CYTHON_INLINE long __Pyx_PyLong_As_long(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const long neg_one = (long) -1, const_zero = (long) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (unlikely(!PyLong_Check(x))) { - long val; - PyObject *tmp = __Pyx_PyNumber_Long(x); - if (!tmp) return (long) -1; - val = __Pyx_PyLong_As_long(tmp); - Py_DECREF(tmp); - return val; - } - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - if (unlikely(__Pyx_PyLong_IsNeg(x))) { - goto raise_neg_overflow; - } else if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_DigitCount(x)) { - case 2: - if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 2 * PyLong_SHIFT)) { - return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 3: - if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 3 * PyLong_SHIFT)) { - return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - case 4: - if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) >= 4 * PyLong_SHIFT)) { - return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); - } - } - break; - } - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (long) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if ((sizeof(long) <= sizeof(unsigned long))) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(long) <= sizeof(unsigned PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(long, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_SignedDigitCount(x)) { - case -2: - if ((8 * sizeof(long) - 1 > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 2: - if ((8 * sizeof(long) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -3: - if ((8 * sizeof(long) - 1 > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 3: - if ((8 * sizeof(long) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case -4: - if ((8 * sizeof(long) - 1 > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { - return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - case 4: - if ((8 * sizeof(long) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(long) - 1 > 4 * PyLong_SHIFT)) { - return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); - } - } - break; - } - } -#endif - if ((sizeof(long) <= sizeof(long))) { - __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(long) <= sizeof(PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { - long val; - int ret = -1; -#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API - Py_ssize_t bytes_copied = PyLong_AsNativeBytes( - x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); - if (unlikely(bytes_copied == -1)) { - } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { - goto raise_overflow; - } else { - ret = 0; - } -#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - ret = _PyLong_AsByteArray((PyLongObject *)x, - bytes, sizeof(val), - is_little, !is_unsigned); -#else - PyObject *v; - PyObject *stepval = NULL, *mask = NULL, *shift = NULL; - int bits, remaining_bits, is_negative = 0; - int chunk_size = (sizeof(long) < 8) ? 30 : 62; - if (likely(PyLong_CheckExact(x))) { - v = __Pyx_NewRef(x); - } else { - v = PyNumber_Long(x); - if (unlikely(!v)) return (long) -1; - assert(PyLong_CheckExact(v)); - } - { - int result = PyObject_RichCompareBool(v, Py_False, Py_LT); - if (unlikely(result < 0)) { - Py_DECREF(v); - return (long) -1; - } - is_negative = result == 1; - } - if (is_unsigned && unlikely(is_negative)) { - Py_DECREF(v); - goto raise_neg_overflow; - } else if (is_negative) { - stepval = PyNumber_Invert(v); - Py_DECREF(v); - if (unlikely(!stepval)) - return (long) -1; - } else { - stepval = v; - } - v = NULL; - val = (long) 0; - mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; - shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; - for (bits = 0; bits < (int) sizeof(long) * 8 - chunk_size; bits += chunk_size) { - PyObject *tmp, *digit; - long idigit; - digit = PyNumber_And(stepval, mask); - if (unlikely(!digit)) goto done; - idigit = PyLong_AsLong(digit); - Py_DECREF(digit); - if (unlikely(idigit < 0)) goto done; - val |= ((long) idigit) << bits; - tmp = PyNumber_Rshift(stepval, shift); - if (unlikely(!tmp)) goto done; - Py_DECREF(stepval); stepval = tmp; - } - Py_DECREF(shift); shift = NULL; - Py_DECREF(mask); mask = NULL; - { - long idigit = PyLong_AsLong(stepval); - if (unlikely(idigit < 0)) goto done; - remaining_bits = ((int) sizeof(long) * 8) - bits - (is_unsigned ? 0 : 1); - if (unlikely(idigit >= (1L << remaining_bits))) - goto raise_overflow; - val |= ((long) idigit) << bits; - } - if (!is_unsigned) { - if (unlikely(val & (((long) 1) << (sizeof(long) * 8 - 1)))) - goto raise_overflow; - if (is_negative) - val = ~val; - } - ret = 0; - done: - Py_XDECREF(shift); - Py_XDECREF(mask); - Py_XDECREF(stepval); -#endif - if (unlikely(ret)) - return (long) -1; - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to long"); - return (long) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to long"); - return (long) -1; -} - -/* CIntFromPy */ -static CYTHON_INLINE int __Pyx_PyLong_As_int(PyObject *x) { -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wconversion" -#endif - const int neg_one = (int) -1, const_zero = (int) 0; -#ifdef __Pyx_HAS_GCC_DIAGNOSTIC -#pragma GCC diagnostic pop -#endif - const int is_unsigned = neg_one > const_zero; - if (unlikely(!PyLong_Check(x))) { - int val; - PyObject *tmp = __Pyx_PyNumber_Long(x); - if (!tmp) return (int) -1; - val = __Pyx_PyLong_As_int(tmp); - Py_DECREF(tmp); - return val; - } - if (is_unsigned) { -#if CYTHON_USE_PYLONG_INTERNALS - if (unlikely(__Pyx_PyLong_IsNeg(x))) { - goto raise_neg_overflow; - } else if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_upylong, __Pyx_PyLong_CompactValueUnsigned(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_DigitCount(x)) { - case 2: - if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 2 * PyLong_SHIFT)) { - return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 3: - if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 3 * PyLong_SHIFT)) { - return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - case 4: - if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) >= 4 * PyLong_SHIFT)) { - return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); - } - } - break; - } - } -#endif -#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX < 0x030C00A7 - if (unlikely(Py_SIZE(x) < 0)) { - goto raise_neg_overflow; - } -#else - { - int result = PyObject_RichCompareBool(x, Py_False, Py_LT); - if (unlikely(result < 0)) - return (int) -1; - if (unlikely(result == 1)) - goto raise_neg_overflow; - } -#endif - if ((sizeof(int) <= sizeof(unsigned long))) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(int) <= sizeof(unsigned PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) -#endif - } - } else { -#if CYTHON_USE_PYLONG_INTERNALS - if (__Pyx_PyLong_IsCompact(x)) { - __PYX_VERIFY_RETURN_INT(int, __Pyx_compact_pylong, __Pyx_PyLong_CompactValue(x)) - } else { - const digit* digits = __Pyx_PyLong_Digits(x); - assert(__Pyx_PyLong_DigitCount(x) > 1); - switch (__Pyx_PyLong_SignedDigitCount(x)) { - case -2: - if ((8 * sizeof(int) - 1 > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 2: - if ((8 * sizeof(int) > 1 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 2 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -3: - if ((8 * sizeof(int) - 1 > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 3: - if ((8 * sizeof(int) > 2 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 3 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case -4: - if ((8 * sizeof(int) - 1 > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { - return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - case 4: - if ((8 * sizeof(int) > 3 * PyLong_SHIFT)) { - if ((8 * sizeof(unsigned long) > 4 * PyLong_SHIFT)) { - __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) - } else if ((8 * sizeof(int) - 1 > 4 * PyLong_SHIFT)) { - return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); - } - } - break; - } - } -#endif - if ((sizeof(int) <= sizeof(long))) { - __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) -#ifdef HAVE_LONG_LONG - } else if ((sizeof(int) <= sizeof(PY_LONG_LONG))) { - __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) -#endif - } - } - { - int val; - int ret = -1; -#if PY_VERSION_HEX >= 0x030d00A6 && !CYTHON_COMPILING_IN_LIMITED_API - Py_ssize_t bytes_copied = PyLong_AsNativeBytes( - x, &val, sizeof(val), Py_ASNATIVEBYTES_NATIVE_ENDIAN | (is_unsigned ? Py_ASNATIVEBYTES_UNSIGNED_BUFFER | Py_ASNATIVEBYTES_REJECT_NEGATIVE : 0)); - if (unlikely(bytes_copied == -1)) { - } else if (unlikely(bytes_copied > (Py_ssize_t) sizeof(val))) { - goto raise_overflow; - } else { - ret = 0; - } -#elif PY_VERSION_HEX < 0x030d0000 && !(CYTHON_COMPILING_IN_PYPY || CYTHON_COMPILING_IN_LIMITED_API) || defined(_PyLong_AsByteArray) - int one = 1; int is_little = (int)*(unsigned char *)&one; - unsigned char *bytes = (unsigned char *)&val; - ret = _PyLong_AsByteArray((PyLongObject *)x, - bytes, sizeof(val), - is_little, !is_unsigned); -#else - PyObject *v; - PyObject *stepval = NULL, *mask = NULL, *shift = NULL; - int bits, remaining_bits, is_negative = 0; - int chunk_size = (sizeof(long) < 8) ? 30 : 62; - if (likely(PyLong_CheckExact(x))) { - v = __Pyx_NewRef(x); - } else { - v = PyNumber_Long(x); - if (unlikely(!v)) return (int) -1; - assert(PyLong_CheckExact(v)); - } - { - int result = PyObject_RichCompareBool(v, Py_False, Py_LT); - if (unlikely(result < 0)) { - Py_DECREF(v); - return (int) -1; - } - is_negative = result == 1; - } - if (is_unsigned && unlikely(is_negative)) { - Py_DECREF(v); - goto raise_neg_overflow; - } else if (is_negative) { - stepval = PyNumber_Invert(v); - Py_DECREF(v); - if (unlikely(!stepval)) - return (int) -1; - } else { - stepval = v; - } - v = NULL; - val = (int) 0; - mask = PyLong_FromLong((1L << chunk_size) - 1); if (unlikely(!mask)) goto done; - shift = PyLong_FromLong(chunk_size); if (unlikely(!shift)) goto done; - for (bits = 0; bits < (int) sizeof(int) * 8 - chunk_size; bits += chunk_size) { - PyObject *tmp, *digit; - long idigit; - digit = PyNumber_And(stepval, mask); - if (unlikely(!digit)) goto done; - idigit = PyLong_AsLong(digit); - Py_DECREF(digit); - if (unlikely(idigit < 0)) goto done; - val |= ((int) idigit) << bits; - tmp = PyNumber_Rshift(stepval, shift); - if (unlikely(!tmp)) goto done; - Py_DECREF(stepval); stepval = tmp; - } - Py_DECREF(shift); shift = NULL; - Py_DECREF(mask); mask = NULL; - { - long idigit = PyLong_AsLong(stepval); - if (unlikely(idigit < 0)) goto done; - remaining_bits = ((int) sizeof(int) * 8) - bits - (is_unsigned ? 0 : 1); - if (unlikely(idigit >= (1L << remaining_bits))) - goto raise_overflow; - val |= ((int) idigit) << bits; - } - if (!is_unsigned) { - if (unlikely(val & (((int) 1) << (sizeof(int) * 8 - 1)))) - goto raise_overflow; - if (is_negative) - val = ~val; - } - ret = 0; - done: - Py_XDECREF(shift); - Py_XDECREF(mask); - Py_XDECREF(stepval); -#endif - if (unlikely(ret)) - return (int) -1; - return val; - } -raise_overflow: - PyErr_SetString(PyExc_OverflowError, - "value too large to convert to int"); - return (int) -1; -raise_neg_overflow: - PyErr_SetString(PyExc_OverflowError, - "can't convert negative value to int"); - return (int) -1; -} - -/* FastTypeChecks */ -#if CYTHON_COMPILING_IN_CPYTHON -static int __Pyx_InBases(PyTypeObject *a, PyTypeObject *b) { - while (a) { - a = __Pyx_PyType_GetSlot(a, tp_base, PyTypeObject*); - if (a == b) - return 1; - } - return b == &PyBaseObject_Type; -} -static CYTHON_INLINE int __Pyx_IsSubtype(PyTypeObject *a, PyTypeObject *b) { - PyObject *mro; - if (a == b) return 1; - mro = a->tp_mro; - if (likely(mro)) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) - return 1; - } - return 0; - } - return __Pyx_InBases(a, b); -} -static CYTHON_INLINE int __Pyx_IsAnySubtype2(PyTypeObject *cls, PyTypeObject *a, PyTypeObject *b) { - PyObject *mro; - if (cls == a || cls == b) return 1; - mro = cls->tp_mro; - if (likely(mro)) { - Py_ssize_t i, n; - n = PyTuple_GET_SIZE(mro); - for (i = 0; i < n; i++) { - PyObject *base = PyTuple_GET_ITEM(mro, i); - if (base == (PyObject *)a || base == (PyObject *)b) - return 1; - } - return 0; - } - return __Pyx_InBases(cls, a) || __Pyx_InBases(cls, b); -} -static CYTHON_INLINE int __Pyx_inner_PyErr_GivenExceptionMatches2(PyObject *err, PyObject* exc_type1, PyObject *exc_type2) { - if (exc_type1) { - return __Pyx_IsAnySubtype2((PyTypeObject*)err, (PyTypeObject*)exc_type1, (PyTypeObject*)exc_type2); - } else { - return __Pyx_IsSubtype((PyTypeObject*)err, (PyTypeObject*)exc_type2); - } -} -static int __Pyx_PyErr_GivenExceptionMatchesTuple(PyObject *exc_type, PyObject *tuple) { - Py_ssize_t i, n; - assert(PyExceptionClass_Check(exc_type)); - n = PyTuple_GET_SIZE(tuple); - for (i=0; i= 0x030b0000 - return Py_Version & ~0xFFUL; -#else - static unsigned long __Pyx_cached_runtime_version = 0; - if (__Pyx_cached_runtime_version == 0) { - const char* rt_version = Py_GetVersion(); - unsigned long version = 0; - unsigned long factor = 0x01000000UL; - unsigned int digit = 0; - int i = 0; - while (factor) { - while ('0' <= rt_version[i] && rt_version[i] <= '9') { - digit = digit * 10 + (unsigned int) (rt_version[i] - '0'); - ++i; - } - version += factor * digit; - if (rt_version[i] != '.') - break; - digit = 0; - factor >>= 8; - ++i; - } - __Pyx_cached_runtime_version = version; - } - return __Pyx_cached_runtime_version; -#endif -} - -/* CheckBinaryVersion */ -static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt_version, int allow_newer) { - const unsigned long MAJOR_MINOR = 0xFFFF0000UL; - if ((rt_version & MAJOR_MINOR) == (ct_version & MAJOR_MINOR)) - return 0; - if (likely(allow_newer && (rt_version & MAJOR_MINOR) > (ct_version & MAJOR_MINOR))) - return 1; - { - char message[200]; - PyOS_snprintf(message, sizeof(message), - "compile time Python version %d.%d " - "of module '%.100s' " - "%s " - "runtime version %d.%d", - (int) (ct_version >> 24), (int) ((ct_version >> 16) & 0xFF), - __Pyx_MODULE_NAME, - (allow_newer) ? "was newer than" : "does not match", - (int) (rt_version >> 24), (int) ((rt_version >> 16) & 0xFF) - ); - return PyErr_WarnEx(NULL, message, 1); - } -} - -/* InitStrings */ -static int __Pyx_InitStrings(__Pyx_StringTabEntry const *t, PyObject **target, const char* const* encoding_names) { - while (t->s) { - PyObject *str; - if (t->is_unicode) { - if (t->intern) { - str = PyUnicode_InternFromString(t->s); - } else if (t->encoding) { - str = PyUnicode_Decode(t->s, t->n - 1, encoding_names[t->encoding], NULL); - } else { - str = PyUnicode_FromStringAndSize(t->s, t->n - 1); - } - } else { - str = PyBytes_FromStringAndSize(t->s, t->n - 1); - } - if (!str) - return -1; - *target = str; - if (PyObject_Hash(str) == -1) - return -1; - ++t; - ++target; - } - return 0; -} - -#include -static CYTHON_INLINE Py_ssize_t __Pyx_ssize_strlen(const char *s) { - size_t len = strlen(s); - if (unlikely(len > (size_t) PY_SSIZE_T_MAX)) { - PyErr_SetString(PyExc_OverflowError, "byte string is too long"); - return -1; - } - return (Py_ssize_t) len; -} -static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { - Py_ssize_t len = __Pyx_ssize_strlen(c_str); - if (unlikely(len < 0)) return NULL; - return __Pyx_PyUnicode_FromStringAndSize(c_str, len); -} -static CYTHON_INLINE PyObject* __Pyx_PyByteArray_FromString(const char* c_str) { - Py_ssize_t len = __Pyx_ssize_strlen(c_str); - if (unlikely(len < 0)) return NULL; - return PyByteArray_FromStringAndSize(c_str, len); -} -static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) { - Py_ssize_t ignore; - return __Pyx_PyObject_AsStringAndSize(o, &ignore); -} -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 -static CYTHON_INLINE const char* __Pyx_PyUnicode_AsStringAndSize(PyObject* o, Py_ssize_t *length) { - if (unlikely(__Pyx_PyUnicode_READY(o) == -1)) return NULL; -#if CYTHON_COMPILING_IN_LIMITED_API - { - const char* result; - Py_ssize_t unicode_length; - CYTHON_MAYBE_UNUSED_VAR(unicode_length); // only for __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - #if __PYX_LIMITED_VERSION_HEX < 0x030A0000 - if (unlikely(PyArg_Parse(o, "s#", &result, length) < 0)) return NULL; - #else - result = PyUnicode_AsUTF8AndSize(o, length); - #endif - #if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - unicode_length = PyUnicode_GetLength(o); - if (unlikely(unicode_length < 0)) return NULL; - if (unlikely(unicode_length != *length)) { - PyUnicode_AsASCIIString(o); - return NULL; - } - #endif - return result; - } -#else -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII - if (likely(PyUnicode_IS_ASCII(o))) { - *length = PyUnicode_GET_LENGTH(o); - return PyUnicode_AsUTF8(o); - } else { - PyUnicode_AsASCIIString(o); - return NULL; - } -#else - return PyUnicode_AsUTF8AndSize(o, length); -#endif -#endif -} -#endif -static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { -#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_UTF8 - if (PyUnicode_Check(o)) { - return __Pyx_PyUnicode_AsStringAndSize(o, length); - } else -#endif - if (PyByteArray_Check(o)) { -#if (CYTHON_ASSUME_SAFE_SIZE && CYTHON_ASSUME_SAFE_MACROS) || (CYTHON_COMPILING_IN_PYPY && (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE))) - *length = PyByteArray_GET_SIZE(o); - return PyByteArray_AS_STRING(o); -#else - *length = PyByteArray_Size(o); - if (*length == -1) return NULL; - return PyByteArray_AsString(o); -#endif - } else - { - char* result; - int r = PyBytes_AsStringAndSize(o, &result, length); - if (unlikely(r < 0)) { - return NULL; - } else { - return result; - } - } -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { - int is_true = x == Py_True; - if (is_true | (x == Py_False) | (x == Py_None)) return is_true; - else return PyObject_IsTrue(x); -} -static CYTHON_INLINE int __Pyx_PyObject_IsTrueAndDecref(PyObject* x) { - int retval; - if (unlikely(!x)) return -1; - retval = __Pyx_PyObject_IsTrue(x); - Py_DECREF(x); - return retval; -} -static PyObject* __Pyx_PyNumber_LongWrongResultType(PyObject* result) { - __Pyx_TypeName result_type_name = __Pyx_PyType_GetFullyQualifiedName(Py_TYPE(result)); - if (PyLong_Check(result)) { - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "__int__ returned non-int (type " __Pyx_FMT_TYPENAME "). " - "The ability to return an instance of a strict subclass of int is deprecated, " - "and may be removed in a future version of Python.", - result_type_name)) { - __Pyx_DECREF_TypeName(result_type_name); - Py_DECREF(result); - return NULL; - } - __Pyx_DECREF_TypeName(result_type_name); - return result; - } - PyErr_Format(PyExc_TypeError, - "__int__ returned non-int (type " __Pyx_FMT_TYPENAME ")", - result_type_name); - __Pyx_DECREF_TypeName(result_type_name); - Py_DECREF(result); - return NULL; -} -static CYTHON_INLINE PyObject* __Pyx_PyNumber_Long(PyObject* x) { -#if CYTHON_USE_TYPE_SLOTS - PyNumberMethods *m; -#endif - PyObject *res = NULL; - if (likely(PyLong_Check(x))) - return __Pyx_NewRef(x); -#if CYTHON_USE_TYPE_SLOTS - m = Py_TYPE(x)->tp_as_number; - if (likely(m && m->nb_int)) { - res = m->nb_int(x); - } -#else - if (!PyBytes_CheckExact(x) && !PyUnicode_CheckExact(x)) { - res = PyNumber_Long(x); - } -#endif - if (likely(res)) { - if (unlikely(!PyLong_CheckExact(res))) { - return __Pyx_PyNumber_LongWrongResultType(res); - } - } - else if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "an integer is required"); - } - return res; -} -static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { - Py_ssize_t ival; - PyObject *x; - if (likely(PyLong_CheckExact(b))) { - #if CYTHON_USE_PYLONG_INTERNALS - if (likely(__Pyx_PyLong_IsCompact(b))) { - return __Pyx_PyLong_CompactValue(b); - } else { - const digit* digits = __Pyx_PyLong_Digits(b); - const Py_ssize_t size = __Pyx_PyLong_SignedDigitCount(b); - switch (size) { - case 2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -2: - if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -3: - if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case 4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - case -4: - if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { - return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); - } - break; - } - } - #endif - return PyLong_AsSsize_t(b); - } - x = PyNumber_Index(b); - if (!x) return -1; - ival = PyLong_AsSsize_t(x); - Py_DECREF(x); - return ival; -} -static CYTHON_INLINE Py_hash_t __Pyx_PyIndex_AsHash_t(PyObject* o) { - if (sizeof(Py_hash_t) == sizeof(Py_ssize_t)) { - return (Py_hash_t) __Pyx_PyIndex_AsSsize_t(o); - } else { - Py_ssize_t ival; - PyObject *x; - x = PyNumber_Index(o); - if (!x) return -1; - ival = PyLong_AsLong(x); - Py_DECREF(x); - return ival; - } -} -static CYTHON_INLINE PyObject *__Pyx_Owned_Py_None(int b) { - CYTHON_UNUSED_VAR(b); - return __Pyx_NewRef(Py_None); -} -static CYTHON_INLINE PyObject * __Pyx_PyBool_FromLong(long b) { - return b ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False); -} -static CYTHON_INLINE PyObject * __Pyx_PyLong_FromSize_t(size_t ival) { - return PyLong_FromSize_t(ival); -} - - -/* MultiPhaseInitModuleState */ -#if CYTHON_PEP489_MULTI_PHASE_INIT && CYTHON_USE_MODULE_STATE -#ifndef CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -#if (CYTHON_COMPILING_IN_LIMITED_API || PY_VERSION_HEX >= 0x030C0000) - #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 1 -#else - #define CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE 0 -#endif -#endif -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE && !CYTHON_ATOMICS -#error "Module state with PEP489 requires atomics. Currently that's one of\ - C11, C++11, gcc atomic intrinsics or MSVC atomic intrinsics" -#endif -#if !CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -#define __Pyx_ModuleStateLookup_Lock() -#define __Pyx_ModuleStateLookup_Unlock() -#elif !CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x030d0000 -static PyMutex __Pyx_ModuleStateLookup_mutex = {0}; -#define __Pyx_ModuleStateLookup_Lock() PyMutex_Lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() PyMutex_Unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(__cplusplus) && __cplusplus >= 201103L -#include -static std::mutex __Pyx_ModuleStateLookup_mutex; -#define __Pyx_ModuleStateLookup_Lock() __Pyx_ModuleStateLookup_mutex.lock() -#define __Pyx_ModuleStateLookup_Unlock() __Pyx_ModuleStateLookup_mutex.unlock() -#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201112L) && !defined(__STDC_NO_THREADS__) -#include -static mtx_t __Pyx_ModuleStateLookup_mutex; -static once_flag __Pyx_ModuleStateLookup_mutex_once_flag = ONCE_FLAG_INIT; -static void __Pyx_ModuleStateLookup_initialize_mutex(void) { - mtx_init(&__Pyx_ModuleStateLookup_mutex, mtx_plain); -} -#define __Pyx_ModuleStateLookup_Lock()\ - call_once(&__Pyx_ModuleStateLookup_mutex_once_flag, __Pyx_ModuleStateLookup_initialize_mutex);\ - mtx_lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() mtx_unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(HAVE_PTHREAD_H) -#include -static pthread_mutex_t __Pyx_ModuleStateLookup_mutex = PTHREAD_MUTEX_INITIALIZER; -#define __Pyx_ModuleStateLookup_Lock() pthread_mutex_lock(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() pthread_mutex_unlock(&__Pyx_ModuleStateLookup_mutex) -#elif defined(_WIN32) -#include // synchapi.h on its own doesn't work -static SRWLOCK __Pyx_ModuleStateLookup_mutex = SRWLOCK_INIT; -#define __Pyx_ModuleStateLookup_Lock() AcquireSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) -#define __Pyx_ModuleStateLookup_Unlock() ReleaseSRWLockExclusive(&__Pyx_ModuleStateLookup_mutex) -#else -#error "No suitable lock available for CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE.\ - Requires C standard >= C11, or C++ standard >= C++11,\ - or pthreads, or the Windows 32 API, or Python >= 3.13." -#endif -typedef struct { - int64_t id; - PyObject *module; -} __Pyx_InterpreterIdAndModule; -typedef struct { - char interpreter_id_as_index; - Py_ssize_t count; - Py_ssize_t allocated; - __Pyx_InterpreterIdAndModule table[1]; -} __Pyx_ModuleStateLookupData; -#define __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE 32 -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static __pyx_atomic_int_type __Pyx_ModuleStateLookup_read_counter = 0; -#endif -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static __pyx_atomic_ptr_type __Pyx_ModuleStateLookup_data = 0; -#else -static __Pyx_ModuleStateLookupData* __Pyx_ModuleStateLookup_data = NULL; -#endif -static __Pyx_InterpreterIdAndModule* __Pyx_State_FindModuleStateLookupTableLowerBound( - __Pyx_InterpreterIdAndModule* table, - Py_ssize_t count, - int64_t interpreterId) { - __Pyx_InterpreterIdAndModule* begin = table; - __Pyx_InterpreterIdAndModule* end = begin + count; - if (begin->id == interpreterId) { - return begin; - } - while ((end - begin) > __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { - __Pyx_InterpreterIdAndModule* halfway = begin + (end - begin)/2; - if (halfway->id == interpreterId) { - return halfway; - } - if (halfway->id < interpreterId) { - begin = halfway; - } else { - end = halfway; - } - } - for (; begin < end; ++begin) { - if (begin->id >= interpreterId) return begin; - } - return begin; -} -static PyObject *__Pyx_State_FindModule(CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return NULL; -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData* data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); - { - __pyx_atomic_incr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); - if (likely(data)) { - __Pyx_ModuleStateLookupData* new_data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_acquire(&__Pyx_ModuleStateLookup_data); - if (likely(data == new_data)) { - goto read_finished; - } - } - __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); - __Pyx_ModuleStateLookup_Lock(); - __pyx_atomic_incr_relaxed(&__Pyx_ModuleStateLookup_read_counter); - data = (__Pyx_ModuleStateLookupData*)__pyx_atomic_pointer_load_relaxed(&__Pyx_ModuleStateLookup_data); - __Pyx_ModuleStateLookup_Unlock(); - } - read_finished:; -#else - __Pyx_ModuleStateLookupData* data = __Pyx_ModuleStateLookup_data; -#endif - __Pyx_InterpreterIdAndModule* found = NULL; - if (unlikely(!data)) goto end; - if (data->interpreter_id_as_index) { - if (interpreter_id < data->count) { - found = data->table+interpreter_id; - } - } else { - found = __Pyx_State_FindModuleStateLookupTableLowerBound( - data->table, data->count, interpreter_id); - } - end: - { - PyObject *result=NULL; - if (found && found->id == interpreter_id) { - result = found->module; - } -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_decr_acq_rel(&__Pyx_ModuleStateLookup_read_counter); -#endif - return result; - } -} -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE -static void __Pyx_ModuleStateLookup_wait_until_no_readers(void) { - while (__pyx_atomic_load(&__Pyx_ModuleStateLookup_read_counter) != 0); -} -#else -#define __Pyx_ModuleStateLookup_wait_until_no_readers() -#endif -static int __Pyx_State_AddModuleInterpIdAsIndex(__Pyx_ModuleStateLookupData **old_data, PyObject* module, int64_t interpreter_id) { - Py_ssize_t to_allocate = (*old_data)->allocated; - while (to_allocate <= interpreter_id) { - if (to_allocate == 0) to_allocate = 1; - else to_allocate *= 2; - } - __Pyx_ModuleStateLookupData *new_data = *old_data; - if (to_allocate != (*old_data)->allocated) { - new_data = (__Pyx_ModuleStateLookupData *)realloc( - *old_data, - sizeof(__Pyx_ModuleStateLookupData)+(to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); - if (!new_data) { - PyErr_NoMemory(); - return -1; - } - for (Py_ssize_t i = new_data->allocated; i < to_allocate; ++i) { - new_data->table[i].id = i; - new_data->table[i].module = NULL; - } - new_data->allocated = to_allocate; - } - new_data->table[interpreter_id].module = module; - if (new_data->count < interpreter_id+1) { - new_data->count = interpreter_id+1; - } - *old_data = new_data; - return 0; -} -static void __Pyx_State_ConvertFromInterpIdAsIndex(__Pyx_ModuleStateLookupData *data) { - __Pyx_InterpreterIdAndModule *read = data->table; - __Pyx_InterpreterIdAndModule *write = data->table; - __Pyx_InterpreterIdAndModule *end = read + data->count; - for (; readmodule) { - write->id = read->id; - write->module = read->module; - ++write; - } - } - data->count = write - data->table; - for (; writeid = 0; - write->module = NULL; - } - data->interpreter_id_as_index = 0; -} -static int __Pyx_State_AddModule(PyObject* module, CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return -1; - int result = 0; - __Pyx_ModuleStateLookup_Lock(); -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData *old_data = (__Pyx_ModuleStateLookupData *) - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); -#else - __Pyx_ModuleStateLookupData *old_data = __Pyx_ModuleStateLookup_data; -#endif - __Pyx_ModuleStateLookupData *new_data = old_data; - if (!new_data) { - new_data = (__Pyx_ModuleStateLookupData *)calloc(1, sizeof(__Pyx_ModuleStateLookupData)); - if (!new_data) { - result = -1; - PyErr_NoMemory(); - goto end; - } - new_data->allocated = 1; - new_data->interpreter_id_as_index = 1; - } - __Pyx_ModuleStateLookup_wait_until_no_readers(); - if (new_data->interpreter_id_as_index) { - if (interpreter_id < __PYX_MODULE_STATE_LOOKUP_SMALL_SIZE) { - result = __Pyx_State_AddModuleInterpIdAsIndex(&new_data, module, interpreter_id); - goto end; - } - __Pyx_State_ConvertFromInterpIdAsIndex(new_data); - } - { - Py_ssize_t insert_at = 0; - { - __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( - new_data->table, new_data->count, interpreter_id); - assert(lower_bound); - insert_at = lower_bound - new_data->table; - if (unlikely(insert_at < new_data->count && lower_bound->id == interpreter_id)) { - lower_bound->module = module; - goto end; // already in table, nothing more to do - } - } - if (new_data->count+1 >= new_data->allocated) { - Py_ssize_t to_allocate = (new_data->count+1)*2; - new_data = - (__Pyx_ModuleStateLookupData*)realloc( - new_data, - sizeof(__Pyx_ModuleStateLookupData) + - (to_allocate-1)*sizeof(__Pyx_InterpreterIdAndModule)); - if (!new_data) { - result = -1; - new_data = old_data; - PyErr_NoMemory(); - goto end; - } - new_data->allocated = to_allocate; - } - ++new_data->count; - int64_t last_id = interpreter_id; - PyObject *last_module = module; - for (Py_ssize_t i=insert_at; icount; ++i) { - int64_t current_id = new_data->table[i].id; - new_data->table[i].id = last_id; - last_id = current_id; - PyObject *current_module = new_data->table[i].module; - new_data->table[i].module = last_module; - last_module = current_module; - } - } - end: -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, new_data); -#else - __Pyx_ModuleStateLookup_data = new_data; -#endif - __Pyx_ModuleStateLookup_Unlock(); - return result; -} -static int __Pyx_State_RemoveModule(CYTHON_UNUSED void* dummy) { - int64_t interpreter_id = PyInterpreterState_GetID(__Pyx_PyInterpreterState_Get()); - if (interpreter_id == -1) return -1; - __Pyx_ModuleStateLookup_Lock(); -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __Pyx_ModuleStateLookupData *data = (__Pyx_ModuleStateLookupData *) - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, 0); -#else - __Pyx_ModuleStateLookupData *data = __Pyx_ModuleStateLookup_data; -#endif - if (data->interpreter_id_as_index) { - if (interpreter_id < data->count) { - data->table[interpreter_id].module = NULL; - } - goto done; - } - { - __Pyx_ModuleStateLookup_wait_until_no_readers(); - __Pyx_InterpreterIdAndModule* lower_bound = __Pyx_State_FindModuleStateLookupTableLowerBound( - data->table, data->count, interpreter_id); - if (!lower_bound) goto done; - if (lower_bound->id != interpreter_id) goto done; - __Pyx_InterpreterIdAndModule *end = data->table+data->count; - for (;lower_boundid = (lower_bound+1)->id; - lower_bound->module = (lower_bound+1)->module; - } - } - --data->count; - if (data->count == 0) { - free(data); - data = NULL; - } - done: -#if CYTHON_MODULE_STATE_LOOKUP_THREAD_SAFE - __pyx_atomic_pointer_exchange(&__Pyx_ModuleStateLookup_data, data); -#else - __Pyx_ModuleStateLookup_data = data; -#endif - __Pyx_ModuleStateLookup_Unlock(); - return 0; -} -#endif - -/* #### Code section: utility_code_pragmas_end ### */ -#ifdef _MSC_VER -#pragma warning( pop ) -#endif - - - -/* #### Code section: end ### */ -#endif /* Py_PYTHON_H */ diff --git a/epanet/epanet2_ec.py b/epanet/epanet2_ec.py deleted file mode 100644 index c0df16b..0000000 --- a/epanet/epanet2_ec.py +++ /dev/null @@ -1,92 +0,0 @@ -ERROR_CODE = {} - -# EPANET 2 Error Messages -ERROR_CODE['0'] = "ok" - -ERROR_CODE['10'] = "Warning: model run issued warnings" - -ERROR_CODE['101'] = "insufficient memory available" -ERROR_CODE['102'] = "no network data available" -ERROR_CODE['103'] = "hydraulic solver not opened" -ERROR_CODE['104'] = "no hydraulics for water quality analysis" -ERROR_CODE['105'] = "water quality solver not opened" -ERROR_CODE['106'] = "no results saved to report on" -ERROR_CODE['107'] = "hydraulics supplied from external file" -ERROR_CODE['108'] = "cannot use external file while hydraulics solver is active" -ERROR_CODE['110'] = "cannot solve network hydraulic equations" -ERROR_CODE['120'] = "cannot solve water quality transport equations" - -# These errors apply only to an input file -ERROR_CODE['200'] = "one or more errors in input file" -ERROR_CODE['201'] = "syntax error" - -# These errors apply to both an input file and to API functions -ERROR_CODE['202'] = "illegal numeric value" -ERROR_CODE['203'] = "undefined node" -ERROR_CODE['204'] = "undefined link" -ERROR_CODE['205'] = "undefined time pattern" -ERROR_CODE['206'] = "undefined curve" -ERROR_CODE['207'] = "attempt to control CV/GPV link" -ERROR_CODE['208'] = "illegal PDA pressure limits" -ERROR_CODE['209'] = "illegal node property value" -ERROR_CODE['211'] = "illegal link property value" -ERROR_CODE['212'] = "undefined trace node" -ERROR_CODE['213'] = "invalid option value" -ERROR_CODE['214'] = "too many characters in input line" -ERROR_CODE['215'] = "duplicate ID label" -ERROR_CODE['216'] = "reference to undefined pump" -ERROR_CODE['217'] = "invalid pump energy data" -ERROR_CODE['219'] = "illegal valve connection to tank node" -ERROR_CODE['220'] = "illegal valve connection to another valve" -ERROR_CODE['221'] = "mis-placed rule clause in rule-based control" -ERROR_CODE['222'] = "same start and end nodes for link" - -# These errors apply to network consistency check -ERROR_CODE['223'] = "not enough nodes in network" -ERROR_CODE['224'] = "no tanks or reservoirs in network" -ERROR_CODE['225'] = "invalid lower/upper levels for tank" -ERROR_CODE['226'] = "no head curve or power rating for pump" -ERROR_CODE['227'] = "invalid head curve for pump" -ERROR_CODE['230'] = "nonincreasing x-values for curve" -ERROR_CODE['233'] = "network has unconnected nodes" -ERROR_CODE['234'] = "network has an unconnected node with ID: " - -# These errors apply only to API functions -ERROR_CODE['240'] = "nonexistent source" -ERROR_CODE['241'] = "nonexistent control" -ERROR_CODE['250'] = "invalid format" -ERROR_CODE['251'] = "invalid parameter code" -ERROR_CODE['252'] = "invalid ID name" -ERROR_CODE['253'] = "nonexistent demand category" -ERROR_CODE['254'] = "node with no coordinates" -ERROR_CODE['255'] = "invalid link vertex" -ERROR_CODE['257'] = "nonexistent rule" -ERROR_CODE['258'] = "nonexistent rule clause" -ERROR_CODE['259'] = "attempt to delete a node that still has links connected to it" -ERROR_CODE['260'] = "attempt to delete node assigned as a Trace Node" -ERROR_CODE['261'] = "attempt to delete a node or link contained in a control" -ERROR_CODE['262'] = "attempt to modify network structure while solver is active" -ERROR_CODE['263'] = "node is not a tank" - -# File errors -ERROR_CODE['301'] = "identical file names" -ERROR_CODE['302'] = "cannot open input file" -ERROR_CODE['303'] = "cannot open report file" -ERROR_CODE['304'] = "cannot open binary output file" -ERROR_CODE['305'] = "cannot open hydraulics file" -ERROR_CODE['306'] = "hydraulics file does not match network data" -ERROR_CODE['307'] = "cannot read hydraulics file" -ERROR_CODE['308'] = "cannot save results to file" -ERROR_CODE['309'] = "cannot save results to report file" - -ERROR_CODE['411'] = "Input Error 411: no memory allocated for results" -ERROR_CODE['412'] = "Input Error 412: binary file hasn't been opened" -ERROR_CODE['421'] = "Input Error 421: invalid parameter code" -ERROR_CODE['422'] = "Input Error 422: reporting period index out of range" -ERROR_CODE['423'] = "Input Error 423: element index out of range" - -ERROR_CODE['434'] = "File Error 434: unable to open binary file" -ERROR_CODE['435'] = "File Error 435: invalid binary file type" -ERROR_CODE['436'] = "File Error 436: no results in binary file" - -ERROR_CODE['ERR'] = "Error: An unknown error has occurred" diff --git a/epanet/epanet2_vs_3.md b/epanet/epanet2_vs_3.md deleted file mode 100644 index c66a9b6..0000000 --- a/epanet/epanet2_vs_3.md +++ /dev/null @@ -1,187 +0,0 @@ -### Introduction - -This document summarizes how EPANET 3 differs from EPANET 2. - -_ALL ITEMS ARE SUBJECT TO CHANGE AS EPANET 3 UNDERGOES ADDITIONAL DEVELOPMENT._ - -### Input File Format - -EPANET 3 is capable of reading EPANET 2 input files. However several keywords in the **[OPTIONS]** section of the file were changed to provide more clarity and consistency. The changes are as follows: - -| Old Keyword | New Keyword | -| ------------------ | -------------------- | -| UNITS | FLOW_UNITS | -| PRESSURE | PRESSURE_UNITS | -| HEADLOSS | HEADLOSS_MODEL | -| QUALITY | QUALITY_MODEL | -| VISCOSITY | SPECIFIC_VISCOSITY | -| DIFFUSIVITY | SPECIFIC_DIFFUSIVITY | -| SPECIFIC GRAVITY | SPECIFIC_GRAVITY | -| TRIALS | MAXIMUM_TRIALS | -| ACCURACY | RELATIVE_ACCURACY | -| UNBALANCED | IF_UNBALANCED | -| PATTERN | DEMAND_PATTERN | -| DEMAND MULTIPLIER | DEMAND_MULTIPLIER | -| EMITTER EXPONENT | EMITTER_EXPONENT | -| TOLERANCE | QUALITY_TOLERANCE | -| HYDRAULICS | HYDRAULICS_FILE | -| MAP | MAP_FILE | -| CHECKFREQ | deprecated | -| MAXCHECK | deprecated | -| DAMPlIMIT | deprecated | - -In addition, a number of new keywords have been added to the **[OPTIONS]** section to implement new features added to the code. These are listed below and are covered in more detail in other sections of this document. - -| New Option Keyword | Meaning | -| -------------------- | ------------------------------------------------ | -| DEMAND_MODEL | Choice of pressure-dependent demand model | -| LEAKAGE_MODEL | Choice of pipe leakage model | -| HYDRAULIC_SOLVER | Choice of hydraulic solver | -| MATRIX_SOLVER | Choice of linear equation solver | -| HEAD_TOLERANCE | Tolerance in satisfying head loss equations | -| FLOW_TOLERANCE | Tolerance in satisfying flow continuity | -| FLOW_CHANGE_LIMIT | Convergence limit on link flow change | -| STEP_SIZING | Choice of step sizing method in solving hydraulics | -| TIME_WEIGHT | Backwards difference weight for dynamic tanks | -| MINIMUM_PRESSURE | Global pressure below which demand is zero | -| SERVICE_PRESSURE | Global pressure above which full demand is met | -| PRESSURE_EXPONENT | Global exponent in power demand model | -| LEAKAGE_COEFF1 | Global coefficient used for pipe leakage | -| LEAKAGE_COEFF2 | Global coefficient used for pipe leakage | -| QUALITY_NAME | Name of chemical in water quality analysis | -| QUALITY_UNITS | Concentration units of water quality chemical | -| TRACE_NODE | Name of source node in a water quality trace | - -The **_DURATION_** keyword in the **[TIMES]** section of the file has been replaced with **_TOTAL DURATION_** to make it compatible with the other [TIMES] options that use a pair of keywords. - -In the **[REPORT]** section of the file, **_PAGESIZE_** has been deprecated and the **_STATUS_** option has been split into two separate options, **_STATUS_** **YES/NO** for status reporting and **_TRIALS_** **YES/NO** for reporting individual trials of the hydraulic solver. - -Finally, the names used to identify network elements (e.g., nodes, links, patterns, curves, etc.) are no longer limited to 31 characters. They are, however, still case sensitive. - -### Models and Solvers - -The computational elements in EPANET can be broken down into models for representing particular aspects of network behavior (e.g., pipe head loss, pressure-dependent demands, water quality reactions, etc.) and solvers that compute output results (e.g., hydraulic, sparse matrix, and water quality solvers). EPANET 3 is structured so that its models and solvers are represented by a set of abstract classes that adhere to a specific interface. This makes it easier (in theory) to add alternative models and solvers in the future with a minimum of disruption to the existing code base. The table below lists the **[OPTIONS]** keywords used to specify a choice of model or solver. - -| Option Keyword | Available Choices | -| ---------------- | ------------------------------ | -| HEADLOSS_MODEL | H-W (Hazen-Williams) | -| | D-W (Darcy-Weisbach) | -| | C-M (Chezy-Manning) | -| DEMAND_MODEL | FIXED | -| | CONSTRAINED | -| | POWER | -| | LOGISTIC | -| LEAKAGE_MODEL | NONE | -| | POWER | -| | FAVAD | -| QUALITY_MODEL | NONE | -| | CHEMICAL | -| | TRACE | -| | AGE | -| HYDRAULIC_SOLVER | GGA (Global Gradient Algorithm | -| QUALITY_SOLVER | LTD (Lagrangian Time Driven) | -| MATRIX_SOLVER | SPARSPAK | - -Right now there is only a single choice of each solver but additional alternatives could be added at a later date. Implementations of the various models and solvers can be found in the _Models/_ and _Solvers/_ directories, respectively. - -### API (Toolkit) Usage - -The way in which the API functions are used to analyze a network have changed. The differences between the version 2 and 3 APIs can be summarized as follows: -* Function names now begin with an "EN_" prefix followed by a name in lower camel case. -* You must first call **_EN_createProject_** to create an EPANET project object before using other API functions that include the project as an argument. This allows one to use parallel processing on a number of different projects in a thread safe manner. -* **_ENopen_** has been replaced with **_EN_openReportFile_**, **_EN_openOutputFile_**, and **_EN_loadProject_**. -* **_EN_initSolver_** replaces **_ENopenH_**, **_ENinitH_**, **_ENopenQ_** and **_ENinitQ_**. -* **_EN_runSolver_** replaces **_ENrunH_** for computing hydraulics at the current time period. -* **_EN_advanceSolver_** replaces **_ENnextH_**, **_EN_runQ_**, and **_ENnextQ_**. It advances the simulation to the next time when hydraulics are to be updated while computing water quality over this time interval as need be. -* As implied by the previous item, water quality is now run simultaneously with hydraulics. There is no need to run hydraulics for all time periods first before solving for water quality. -* There is no longer a need for functions like **_ENcloseH_** and **_ENcloseQ_**. You only need to call **_EN_deleteProject_** after all analysis of a project has been completed to insure that all memory is properly released. - -Here is an example of using the new API to run a complete simulation: - -``` -#include "epanet3.h" -void myEpanet3Runner(char* inpFile, char* rptFile) -{ - int t = 0, dt = 0; - EN_Project p = EN_createProject(); - EN_openReportFile(rptFile, p); - EN_loadProject(inpFile, p); - EN_openOutputFile("", p); - EN_initSolver(EN_NOINITFLOW, p); - do { - EN_runSolver(&t, p); - EN_advanceSolver(&dt, p); - } while ( dt > 0 ); - EN_writeReport(p); - EN_deleteProject(p); -} -``` - -### Pressure Dependent Demands - -EPANET 3 offers four different ways of handling consumer demands at network nodes through its **_DEMAND_MODEL_** option: -- **FIXED** (demands are fixed values not dependent on pressure) -- **CONSTRAINED** (demands are reduced so that no net negative pressures occur) -- **POWER** (a node's demand varies as a power function of pressure) -- **LOGISTIC** (a node's demand varies as a logistic function of pressure). - -The **_MINIMUM_PRESSURE_** option is used with choices 2 - 4 to set a pressure below which demand will be 0. Its default value is 0. The **_SERVICE_PRESSURE_** option is used with choices 3 and 4 to set a pressure above which a node's full demand is supplied. The **_PRESSURE_EXPONENT_** option sets the exponent used for **POWER** function demands. - -The implementation of these methods can be found in the _Models/demandmodel.h_ and _Models/demandmodel.cpp_ files as well as in _Core/hydengine.cpp_ for the **CONSTRAINED** option. - -### Pipe Leakage - -Pressure dependent pipe leakage can now be modeled using the new **_LEAKAGE_MODEL_** option. The choices are: -- **NONE** for no leakage modeling. -- **POWER** : -- **FAVAD** : - -For the **Power** model the leakage rate is in flow units/1000 length units of pipe (ft or m), P is the average pressure (psi or m) across the pipe and C1 and C2 are user supplied coefficients. For the **FAVAD** model, the leakage rate is cfs/1000 ft (or cms/km) of pipe, P is the average pressure head (ft or m) across the pipe, C1 is the area (sq. ft. or sq. m) of leaks per 1000 ft or m of pipe and C2 is the change in leakage area per change in pressure head per 1000 length units of pipe. - -The leakage coefficients can be supplied on a global basis using the new option keywords **_LEAKAGE_COEFF1_** and **_LEAKAGE_COEFF2_**. Their default values are 0. The coefficients can also be be supplied on an individual pipe basis by adding a **[LEAKAGE]** section to the input file where each line contains a pipe name and a pair of coefficients. Computed leakage rates are split 50-50 to outflow from the pipe's end nodes. - -Pipe leakage is implemented in the files _Models/leakagemodel.h_, _Models/leakagemodel.cpp_, and _Core/hydbalance.cpp_. - -### Hydraulic Convergence Criteria - -In EPANET 2, convergence to an acceptable hydraulic solution occurred when the sum of all link flow changes divided by the sum of all link flows was below the **_ACCURACY_** (re-named to **_RELATIVE_ACCURACY_**) option value. Unfortunately meeting this criterion did not always guarantee that the network was hydraulically balanced (e.g., that the head loss computed from the flow in each link equaled the difference between the computed heads at the link's end nodes). EPANET 3 introduces a more rigorous set of criteria consisting of the following options: -- **_HEAD_TOLERANCE_** --- the difference between the computed head loss in each link and the heads at its end nodes must be below this value. -- **_FLOW_TOLERANCE_** --- the difference between inflow and outflow at all non-fixed grade nodes must be below this value. -- **_FLOW_CHANGE_LIMIT_** --- the largest change in link flow rate must be below this value. - -The units of the head tolerance are feet (or meters) while the user's choice of flow units apply to the other two. A value of 0 indicates that the criterion doesn't apply. See _Core/hydbalance.h_ and _Core/hydbalance.cpp_ for how the convergence criteria are calculated. - -### Tank Dynamics - -EPANET 2 used a foward difference (or Euler) method to approximate the change in storage tank water level over a time step as a function of the current flows within the network. This could cause instabilities to occur in and around tanks that were hydraulically coupled to one another. To remedy this, EPANET 3 models tank dynamics using the time weighted implicit formula proposed by Todini (2011). A new option named **_TIME_WEIGHT_** sets the weight to be used in this formulation. A value of 0 maintains the forward difference formula of EPANET 2 while a value of 1.0 results in a fully backwards difference formulation. - -### Low Resistance Pipes - -When using the Hazen-Williams (H-W) head loss equation, EPANET 2's hydraulic solver can have problems converging for networks with low resistance or zero flow pipes. To help avoid this, EPANET 3 employs a linear head loss relationship whenever the H-W head loss gradient drops below a minimum threshold (currently set at 1.0e-6 ft/cfs). - -### Check Valves - -The method used by EPANET 2 to find the head loss through an active check valve produced discontinuous gradients and was overly complicated. EPANET 3 uses a simple continuous "barrier" function that is added onto the pipe's normal head loss. It rises rapidly when flow is in the wrong direction but otherwise approaches 0. The details of this function can be found in the _Models/headlossmodel.cpp_ file. - -### Output Variables - -The following quantities have been added to the set of computed results that can be retrieved through the API toolkit: -* node actual demand (which can be less than the full demand due to pressure dependency) -* node total outflow (consisting of actual demand, leakage flow, and emitter flow) -* link leakage flow -* link water quality - -### Binary Output File Format - -The binary file used to store computed results has been modified from the EPANET 2 format to include the new variables reported by EPANET 3. In addition, the file no longer includes the ID names and design data of nodes and links in its prolog section. The new binary file format can be gleaned from the code found in _Output/outputfile.cpp_. - -### Additional Changes -* Emitters are prevented from having flow back into the network. -* The gradient of the Darcy-Weisbach head loss equation now includes the derivative of the friction factor. -* Proper adjustment of the efficiency curve is now made for variable speed pumps. - -### References -Todini (2011) Extending the global gradient algorithm to unsteadyflow extended period simulations of water distributionsystems. Journal of Hydroinformatics, 13(2):167-180 diff --git a/epanet/vcruntime140_1.dll b/epanet/vcruntime140_1.dll deleted file mode 100644 index 3ebabde..0000000 Binary files a/epanet/vcruntime140_1.dll and /dev/null differ diff --git a/infra/docker/docker-compose.yml b/infra/docker/docker-compose.yml new file mode 100644 index 0000000..0131f20 --- /dev/null +++ b/infra/docker/docker-compose.yml @@ -0,0 +1,165 @@ +services: + # ========================================== + # Core API Service + # ========================================== + api: + build: + context: ../.. + dockerfile: infra/docker/Dockerfile + container_name: tjwater_api + restart: always + ports: + - "${API_PORT}:8000" + volumes: + - ../../app:/app/app + - ../../resources:/app/resources + environment: + - PYTHONPATH=/app + - REDIS_HOST=redis + - REDIS_PORT=${REDIS_PORT} + - REDIS_PASSWORD=${REDIS_PASSWORD} + # Add other DB connections here as needed by your app + depends_on: + - redis + - timescaledb + - postgis + + # ========================================== + # Infrastructure Services + # ========================================== + + # --- Redis --- + redis: + image: redis:latest + container_name: redis + restart: always + command: redis-server --requirepass ${REDIS_PASSWORD} + ports: + - "${REDIS_PORT}:6379" + volumes: + - ./redis/data:/data + + # --- InfluxDB --- + influxdb: + image: influxdb:2.7 + container_name: influxdb + restart: always + environment: + DOCKER_INFLUXDB_INIT_MODE: setup + DOCKER_INFLUXDB_INIT_USERNAME: ${INFLUXDB_USER} + DOCKER_INFLUXDB_INIT_PASSWORD: ${INFLUXDB_PASSWORD} + DOCKER_INFLUXDB_INIT_ORG: ${INFLUXDB_ORG} + DOCKER_INFLUXDB_INIT_BUCKET: ${INFLUXDB_BUCKET} + DOCKER_INFLUXDB_INIT_ADMIN_TOKEN: ${INFLUXDB_ADMIN_TOKEN} + ports: + - "${INFLUXDB_PORT}:8086" + volumes: + - ./influxdb/data:/var/lib/influxdb2 + + # --- Keycloak --- + keycloakDB: + image: postgis/postgis:14-3.5 + container_name: keycloakDB + restart: always + environment: + POSTGRES_DB: ${KEYCLOAK_DB_NAME} + POSTGRES_USER: ${KEYCLOAK_DB_USER} + POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD} + command: postgres -c wal_level=logical + ports: + - "${KEYCLOAK_DB_PORT}:5432" + volumes: + - ./keycloak/db_data:/var/lib/postgresql/data + + keycloak: + image: keycloak/keycloak:latest + container_name: keycloak + restart: always + environment: + KC_HOSTNAME: localhost + KC_HOSTNAME_STRICT_BACKCHANNEL: "true" + KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN_USER} + KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} + KC_HEALTH_ENABLED: "true" + KC_LOG_LEVEL: info + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://keycloakDB:5432/${KEYCLOAK_DB_NAME} + KC_DB_USERNAME: ${KEYCLOAK_DB_USER} + KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD} + volumes: + - ./keycloak/themes:/opt/keycloak/themes + - ./keycloak/import:/opt/keycloak/data/import + healthcheck: + test: [ "CMD", "curl", "-f", "http://localhost:8080/health/ready" ] + interval: 15s + timeout: 2s + retries: 15 + command: [ "start-dev", "--import-realm" ] + ports: + - "${KEYCLOAK_PORT}:8080" + depends_on: + - keycloakDB + + # --- TimescaleDB & Grafana --- + timescaledb: + image: timescale/timescaledb:latest-pg15 + container_name: timescaledb + restart: always + environment: + POSTGRES_DB: ${TIMESCALE_DB_NAME} + POSTGRES_USER: ${TIMESCALE_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD_SHARED} + ports: + - "${TIMESCALE_PORT}:5432" + volumes: + - ./timescaledb/data:/var/lib/postgresql/data + + grafana: + image: grafana/grafana:latest + container_name: grafana + restart: always + ports: + - "${GRAFANA_PORT}:3000" + depends_on: + - timescaledb + volumes: + - ./timescaledb/grafana_data:/var/lib/grafana + environment: + - GF_SECURITY_ADMIN_USER=${GRAFANA_ADMIN_USER} + - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD} + + # --- MapService (PostGIS & GeoServer) --- + postgis: + image: postgis/postgis:14-3.5 + container_name: postgis + restart: always + environment: + POSTGRES_DB: ${POSTGIS_DB_NAME} + POSTGRES_USER: ${POSTGIS_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD_SHARED} + ports: + - "${POSTGIS_PORT}:5432" + volumes: + - ./mapservice/data:/var/lib/postgresql/data + + geoserver: + image: docker.osgeo.org/geoserver:2.27.1 + container_name: geoserver + restart: always + ports: + - "${GEOSERVER_PORT}:8080" + depends_on: + - postgis + environment: + - GEOSERVER_ADMIN_USER=${GEOSERVER_ADMIN_USER} + - GEOSERVER_ADMIN_PASSWORD=${GEOSERVER_ADMIN_PASSWORD} + - INSTALL_EXTENSIONS=true + - STABLE_EXTENSIONS=vectortiles + - CORS_ENABLED=true + - CORS_ALLOWED_ORIGINS=* + volumes: + - ./mapservice/geoserver_data:/opt/geoserver_data + +networks: + default: + driver: bridge diff --git a/main - 副本.py b/main - 副本.py deleted file mode 100644 index 91bddb3..0000000 --- a/main - 副本.py +++ /dev/null @@ -1,1808 +0,0 @@ -import os -import io -import json -import time -from typing import * -from urllib.request import Request -from xml.dom import minicompat -from pydantic import BaseModel -from starlette.responses import FileResponse, JSONResponse -from fastapi import FastAPI, File, UploadFile, Response, status, Request, Body, HTTPException -from fastapi.responses import PlainTextResponse -from fastapi.middleware.gzip import GZipMiddleware -from tjnetwork import * -import asyncio -import threading -from multiprocessing import Value - -JUNCTION = 0 -RESERVOIR = 1 -TANK = 2 -PIPE = 1 -NODE_COUNT = 0 -LINK_COUNT = 2 - -prjs = [] -inpDir = "C:/inpfiles/" -tmpDir = "C:/tmpfiles/" - -lockedPrjs = {} - -if not os.path.exists(inpDir): - os.mkdir(inpDir) - -if not os.path.exists(tmpDir): - os.mkdir(tmpDir) - -app = FastAPI() - -# 定义一个共享变量 -lock_simulation = Value('i', 0) - -app.add_middleware(GZipMiddleware, minimum_size=1000) - -############################################################ -# extension_data -############################################################ -@app.get('/getallextensiondatakeys/') -async def fastapi_get_all_extension_data_keys(network: str) -> list[str]: - return get_all_extension_data_keys(network) - -@app.get('/getallextensiondata/') -async def fastapi_get_all_extension_data(network: str) -> dict[str, Any]: - return get_all_extension_data(network) - -@app.get('/getextensiondata/') -async def fastapi_get_extension_data(network: str, key: str) -> str | None: - return get_extension_data(network, key) - -@app.post('/setextensiondata',response_model=None) -async def fastapi_set_extension_data(network: str, req: Request) -> ChangeSet: - props = await req.json() - print(props) - cs = set_extension_data(network, ChangeSet(props)) - print(cs.operations[0]) - return cs - -############################################################ -# project -############################################################ - -@app.get('/listprojects/') -async def fastapi_list_projects() -> list[str]: - return list_project() - -@app.get("/haveproject/") -async def fastapi_have_project(network: str): - return have_project(network) - -@app.post("/createproject/") -async def fastapi_create_project(network: str): - create_project(network) - return network - -@app.post("/deleteproject/") -async def fastapi_delete_project(network: str): - delete_project(network) - return True - -@app.get("/isprojectopen/") -async def fastapi_is_project_open(network: str): - return is_project_open(network) - -@app.post("/openproject/") -async def fastapi_open_project(network: str): - open_project(network) - return network - -@app.post("/closeproject/") -async def fastapi_close_project(network: str): - close_project(network) - return True - -@app.post("/copyproject/") -async def fastapi_copy_project(source: str, target: str): - copy_project(source, target) - return True - -@app.post("/importinp/") -async def fastapi_import_inp(network: str, req: Request): - jo_root = await req.json() - inp_text = jo_root['inp'] - ps = { - "inp" : inp_text - } - ret = import_inp(network, ChangeSet(ps)) - print(ret) - return ret - -@app.get("/exportinp/",response_model=None) -async def fastapi_export_inp(network: str, version: str) -> ChangeSet: - cs = export_inp(network, version) - op = cs.operations[0] - open_project(network) - op['vertex'] = json.dumps(get_all_vertices(network)) - op['scada'] = json.dumps(get_all_scada_elements(network)) - op['dma'] = json.dumps(get_all_district_metering_areas(network)) - op['sa'] = json.dumps(get_all_service_areas(network)) - op['vd'] = json.dumps(get_all_virtual_districts(network)) - op['legend'] = get_extension_data(network, 'legend') - - db = get_extension_data(network, 'scada_db') - print(db) - scada_db = '' - if db: - scada_db = db - print(scada_db) - op['scada_db'] = scada_db - - close_project(network) - - return cs - -@app.post("/readinp/") -async def fastapi_read_inp(network: str, inp: str) -> bool: - read_inp(network, inp) - return True - -@app.get("/dumpinp/") -async def fastapi_dump_inp(network: str, inp: str) -> bool: - dump_inp(network, inp) - return True - -# 必须用这个PlainTextResponse,不然每个key都有引号 -@app.get("/runproject/", response_class = PlainTextResponse) -async def fastapi_run_project(network: str) -> str: - filename = 'c:/lock.simulation' - filename2 = 'c:/lock.simulation2' - if os.path.exists(filename2): - print('file exists') - raise HTTPException(status_code=409, detail="is in simulation") - else: - print('file doesnt exists') - os.rename(filename, filename2) - result = run_project(network) - os.rename(filename2, filename) - return result - -# put in inp folder, name without extension -@app.get("/runinp/") -async def fastapi_run_inp(network: str) -> str: - return run_inp(network) - -# path is absolute path -@app.get("/dumpoutput/") -async def fastapi_dump_output(output: str) -> str: - return dump_output(output) - -@app.get("/isprojectlocked/") -async def fastapi_is_locked(network: str, req: Request): - return str in lockedPrjs.keys() - -@app.get("/isprojectlockedbyme/") -async def fastapi_is_locked_by_me(network: str, req: Request): - client_host = req.client.host - return lockedPrjs.get(network) == client_host - -# 0 successfully locked -# 1 already locked by you -# 2 locked by others -@app.post("/lockproject/") -async def fastapi_lock_project(network: str, req: Request): - client_host = req.client.host - if not network in lockedPrjs.keys(): - lockedPrjs[network] = client_host - return 0 - else: - if lockedPrjs.get(network) == client_host: - return 1 - else: - return 2 - -@app.post("/unlockproject/") -def fastapi_unlock_project(network: str, req: Request): - client_host = req.client.host - if lockedPrjs[network] == client_host: - print("delete key") - del lockedPrjs[network] - return True - - return False - -### operations - -@app.get('/getcurrentoperationid/') -async def fastapi_get_current_operaiton_id(network: str) -> int: - return get_current_operation(network) - -@app.post('/undo/') -async def fastapi_undo(network: str): - return execute_undo(network) - -@app.post('/redo/') -async def fastapi_redo(network: str): - return execute_redo(network) - -@app.get('/getsnapshots/') -def fastapi_list_snapshot(network: str) -> list[tuple[int, str]]: - return list_snapshot(network) - -@app.get('/havesnapshot/') -async def fastapi_have_snapshot(network: str, tag: str) -> bool: - return have_snapshot(network, tag) - -@app.get('/havesnapshotforoperation/') -async def fastapi_have_snapshot_for_operation(network: str, operation: int) -> bool: - return have_snapshot_for_operation(network, operation) - -@app.get('/havesnapshotforcurrentoperation/') -async def fastapi_have_snapshot_for_current_operation(network: str) -> bool: - return have_snapshot_for_current_operation(network) - -@app.post('/takesnapshotforoperation/') -async def fastapi_take_snapshot_for_operation(network: str, operation: int, tag: str) -> None: - return take_snapshot_for_operation(network, operation, tag) - -@app.post('takenapshotforcurrentoperation') -async def fastapi_take_snapshot_for_current_operation(network: str, tag: str) -> None: - return take_snapshot_for_current_operation(network, tag) - -@app.post('/takesnapshot/') -def fastapi_take_snapshot(network: str, tag: str) -> None: - return take_snapshot(network, tag) - -@app.post('/picksnapshot/',response_model=None) -def fastapi_pick_snapshot(network: str, tag: str, discard: bool = False) -> ChangeSet: - return pick_snapshot(network, tag, discard) - -@app.post('/pickoperation/',response_model=None) -async def fastapi_pick_operation(network: str, operation: int, discard: bool = False) -> ChangeSet: - return pick_operation(network, operation, discard) - -@app.get("/syncwithserver/",response_model=None) -async def fastapi_sync_with_server(network: str, operation: int) -> ChangeSet: - return sync_with_server(network, operation) - -@app.post("/batch/",response_model=None) -async def fastapi_execute_batch_commands(network: str, req: Request)-> ChangeSet: - jo_root = await req.json() - cs: ChangeSet = ChangeSet() - cs.operations = jo_root['operations'] - rcs = execute_batch_commands(network, cs) - return rcs - -@app.post("/compressedbatch/",response_model=None) -async def fastapi_execute_compressed_batch_commands(network: str, req: Request)-> ChangeSet: - jo_root = await req.json() - cs: ChangeSet = ChangeSet() - cs.operations = jo_root['operations'] - return execute_batch_command(network, cs) - -@app.get("/getrestoreoperation/") -async def fastapi_get_restore_operation(network : str) -> int: - return get_restore_operation(network) - -@app.post("/setrestoreoperation/") -async def fastapi_set_restore_operation(network: str, operation: int) -> None: - return set_restore_operation(network, operation) - -############################################################ -# type -############################################################ - -@app.get('/isnode/') -async def fastapi_is_node(network: str, node: str) -> bool: - return is_node(network, node) - -@app.get('/isjunction/') -async def fastapi_is_junction(network: str, node: str) -> bool: - return is_junction(network, node) - -@app.get('/isreservoir/') -async def fastapi_is_reservoir(network: str, node: str) -> bool: - return is_reservoir(network, node) - -@app.get('/istank/') -async def fastapi_is_tank(network: str, node: str) -> bool: - return is_tank(network, node) - -@app.get('/islink/') -async def fastapi_is_link(network: str, link: str) -> bool: - return is_link(network, link) - -@app.get('/ispipe/') -async def fastapi_is_pipe(network: str, link: str) -> bool: - return is_pipe(network, link) - -@app.get('/ispump/') -async def fastapi_is_pump(network: str, link: str) -> bool: - return is_pump(network, link) - -@app.get('/isvalve/') -async def fastapi_is_valve(network: str, link: str) -> bool: - return is_valve(network, link) - -@app.get('/iscurve/') -async def fastapi_is_curve(network: str, curve: str) -> bool: - return is_curve(network, curve) - -@app.get('/ispattern/') -async def fastapi_is_pattern(network: str, pattern: str) -> bool: - return is_pattern(network, pattern) - -@app.get("/getnodes/") -async def fastapi_get_nodes(network: str) -> list[str]: - return get_nodes(network) - -@app.get("/getlinks/") -async def fastapi_get_links(network: str) -> list[str]: - return get_links(network) - -@app.get("/getcurves/") -async def fastapi_get_curves(network: str) -> list[str]: - return get_curves(network) - -@app.get("/getpatterns/") -async def fastapi_get_patterns(network: str) -> list[str]: - return get_patterns(network) - -@app.get("/getnodelinks/") -def get_node_links(network: str, node: str) -> list[str]: - return get_node_links(network, node) - -############################################################ -# title 1.[TITLE] -############################################################ -@app.get('/gettitleschema/') -async def fast_get_title_schema(network: str) -> dict[str, dict[str, Any]]: - return get_title_schema(network) - -@app.get('/gettitle/') -async def fast_get_title(network: str) -> dict[str, Any]: - return get_title(network) - -@app.get('/settitle/',response_model=None) -async def fastapi_set_title(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_title(network, ChangeSet(props)) - -############################################################ -# junction 2.[JUNCTIONS] -############################################################ -@app.get('/getjunctionschema') -async def fast_get_junction_schema(network: str) -> dict[str, dict[str, Any]]: - return get_junction_schema(network) - -@app.post("/addjunction/",response_model=None) -async def fastapi_add_junction(network: str, junction: str, x: float, y: float, z: float) -> ChangeSet: - ps = { 'id' : junction, - 'x' : x, - 'y' : y, - 'elevation' : z } - return add_junction(network, ChangeSet(ps)) - -@app.post("/deletejunction/",response_model=None) -async def fastapi_delete_junction(network: str, junction: str) -> ChangeSet: - ps = {'id' : junction} - return delete_junction(network, ChangeSet(ps)) - -@app.get("/getjunctionelevation/") -async def fastapi_get_junction_elevation(network: str, junction: str) -> float: - ps = get_junction(network, junction) - return ps['elevation'] - -@app.get("/getjunctionx/") -async def fastapi_get_junction_x(network: str, junction: str) -> float: - ps = get_junction(network, junction) - return ps['x'] - -@app.get("/getjunctiony/") -async def fastapi_get_junction_x(network: str, junction: str) -> float: - ps = get_junction(network, junction) - return ps['y'] - -@app.get("/getjunctioncoord/") -async def fastapi_get_junction_coord(network: str, junction: str) -> dict[str, float]: - ps = get_junction(network, junction) - coord = { 'x' : ps['x'], - 'y' : ps['y'] } - return coord - -@app.get("/getjunctiondemand/") -async def fastapi_get_junction_demand(network: str, junction: str) -> float: - ps = get_junction(network, junction) - return ps['demand'] - -@app.get("/getjunctionpattern/") -async def fastapi_get_junction_pattern(network: str, junction: str) -> str: - ps = get_junction(network, junction) - return ps['pattern'] - -@app.post("/setjunctionelevation/",response_model=None) -async def fastapi_set_junction_elevation(network: str, junction: str, elevation: float) -> ChangeSet: - ps = { 'id' : junction, - 'elevation' : elevation } - return set_junction(network, ChangeSet(ps)) - -@app.post("/setjunctionx/",response_model=None) -async def fastapi_set_junction_x(network: str, junction: str, x: float) -> ChangeSet: - ps = { 'id' : junction, - 'x' : x } - return set_junction(network, ChangeSet(ps)) - -@app.post("/setjunctiony/",response_model=None) -async def fastapi_set_junction_y(network: str, junction: str, y: float) -> ChangeSet: - ps = { 'id' : junction, - 'y' : y } - return set_junction(network, ChangeSet(ps)) - -@app.post("/setjunctioncoord/",response_model=None) -async def fastapi_set_junction_coord(network: str, junction: str, x: float, y: float) -> ChangeSet: - ps = { 'id' : junction, - 'x' : x, - 'y' : y } - return set_junction(network, ChangeSet(ps)) - -@app.post("/setjunctiondemand/",response_model=None) -async def fastapi_set_junction_demand(network: str, junction: str, demand: float) -> ChangeSet: - ps = { 'id' : junction, - 'demand' : demand } - return set_junction(network, ChangeSet(ps)) - -@app.post("/setjunctionpattern/",response_model=None) -async def fastapi_set_junction_pattern(network: str, junction: str, pattern: str) -> ChangeSet: - ps = { 'id' : junction, - 'pattern' : pattern } - return set_junction(network, ChangeSet(ps)) - -@app.get("/getjunctionproperties/") -async def fastapi_get_junction_properties(network: str, junction: str) -> dict[str, Any]: - return get_junction(network, junction) - -@app.post("/setjunctionproperties/",response_model=None) -async def fastapi_set_junction_properties(network: str, junction: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : junction } | props - return set_junction(network, ChangeSet(ps)) - -############################################################ -# reservoir 3.[RESERVOIRS] -############################################################ -@app.get('/getreservoirschema') -async def fast_get_reservoir_schema(network: str) -> dict[str, dict[str, Any]]: - return get_reservoir_schema(network) - -@app.post("/addreservoir/",response_model=None) -async def fastapi_add_reservoir(network: str, reservoir: str, x: float, y: float, head: float) -> ChangeSet: - ps = { 'id' : reservoir, - 'x' : x, - 'y' : y, - 'head' : head } - return add_reservoir(network, ChangeSet(ps)) - -@app.post("/deletereservoir/",response_model=None) -async def fastapi_delete_reservoir(network: str, reservoir: str) -> ChangeSet: - ps = { 'id' : reservoir } - return delete_reservoir(network, ChangeSet(ps)) - -@app.get("/getreservoirhead/") -async def fastapi_get_reservoir_head(network: str, reservoir: str) -> float | None: - ps = get_reservoir(network, reservoir) - return ps['head'] - -@app.get("/getreservoirpattern/") -async def fastapi_get_reservoir_pattern(network: str, reservoir: str) -> str | None: - ps = get_reservoir(network, reservoir) - return ps['pattern'] - -@app.get("/getreservoirx/") -async def fastapi_get_reservoir_x(network: str, reservoir: str) -> dict[str, float] | None: - ps = get_reservoir(network, reservoir) - return ps['x'] - -@app.get("/getreservoiry/") -async def fastapi_get_reservoir_y(network: str, reservoir: str) -> dict[str, float] | None: - ps = get_reservoir(network, reservoir) - return ps['y'] - -@app.get("/getreservoircoord/") -async def fastapi_get_reservoir_y(network: str, reservoir: str) -> dict[str, float] | None: - ps = get_reservoir(network, reservoir) - coord = { 'id' : reservoir, - 'x' : ps['x'], - 'y' : ps['y'] } - return coord - -@app.post("/setreservoirhead/",response_model=None) -async def fastapi_set_reservoir_head(network: str, reservoir: str, head: float) -> ChangeSet: - ps = { 'id' : reservoir, - 'head' : head } - return set_reservoir(network, ChangeSet(ps)) - -@app.post("/setreservoirpattern/",response_model=None) -async def fastapi_set_reservoir_pattern(network: str, reservoir: str, pattern: str) -> ChangeSet: - ps = { 'id' : reservoir, - 'pattern' : pattern } - return set_reservoir(network, ChangeSet(ps)) - -@app.post("/setreservoirx/",response_model=None) -async def fastapi_set_reservoir_x(network: str, reservoir: str, x: float) -> ChangeSet: - ps = { 'id' : reservoir, - 'x' : x } - return set_reservoir(network, ChangeSet(ps)) - -@app.post("/setreservoirx/",response_model=None) -async def fastapi_set_reservoir_y(network: str, reservoir: str, y: float) -> ChangeSet: - ps = { 'id' : reservoir, - 'y' : y } - return set_reservoir(network, ChangeSet(ps)) - -@app.post("/setreservoircoord/",response_model=None) -async def fastapi_set_reservoir_y(network: str, reservoir: str, x: float, y: float) -> ChangeSet: - ps = { 'id' : reservoir, - 'x' : x, - 'y' : y } - return set_reservoir(network, ChangeSet(ps)) - -@app.get("/getreservoirproperties/") -async def fastapi_get_reservoir_properties(network: str, reservoir: str) -> dict[str, Any]: - return get_reservoir(network, reservoir) - -@app.post("/setreservoirproperties/",response_model=None) -async def fastapi_set_reservoir_properties(network: str, reservoir: str - , req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : reservoir } | props - return set_reservoir(network, ChangeSet(ps)) - - -############################################################ -# tank 4.[TANKS] -############################################################ -@app.get('/gettankschema') -async def fast_get_tank_schema(network: str) -> dict[str, dict[str, Any]]: - return get_tank_schema(network) - -@app.post("/addtank/",response_model=None) -async def fastapi_add_tank(network: str, tank: str, x: float, y: float, elevation: float, init_level: float = 0, min_level: float = 0, max_level: float = 0, diameter: float = 0, min_vol: float = 0) -> ChangeSet: - ps = { 'id' : tank, - 'x' : x, - 'y' : y, - 'elevation' : elevation, - 'init_level' : init_level, - 'min_level' : min_level, - 'max_level' : max_level, - 'diameter' : diameter, - 'min_vol' : min_vol - } - return add_tank(network, ChangeSet(ps)) - -@app.post("/deletetank/",response_model=None) -async def fastapi_delete_tank(network: str, tank: str) -> ChangeSet: - ps = { 'id' : tank } - return delete_tank(network, ChangeSet(ps)) - -@app.get("/gettankelevation/") -async def fastapi_get_tank_elevation(network: str, tank: str) -> float | None: - ps = get_tank(network, tank) - return ps['elevation'] - -@app.get("/gettankinitlevel/") -async def fastapi_get_tank_init_level(network: str, tank: str) -> float | None: - ps = get_tank(network, tank) - return ps['init_level'] - -@app.get("/gettankminlevel/") -async def fastapi_get_tank_min_level(network: str, tank: str) -> float | None: - ps = get_tank(network, tank) - return ps['min_level'] - -@app.get("/gettankmaxlevel/") -async def fastapi_get_tank_max_level(network: str, tank: str) -> float | None: - ps = get_tank(network, tank) - return ps['max_level'] - -@app.get("/gettankdiameter/") -async def fastapi_get_tank_diameter(network: str, tank: str) -> float | None: - ps = get_tank(network, tank) - return ps['diameter'] - -@app.get("/gettankminvol/") -async def fastapi_get_tank_min_vol(network: str, tank: str) -> float | None: - ps = get_tank(network, tank) - return ps['min_vol'] - -@app.get("/gettankvolcurve/") -async def fastapi_get_tank_vol_curve(network: str, tank: str) -> str | None: - ps = get_tank(network, tank) - return ps['vol_curve'] - -@app.get("/gettankoverflow/") -async def fastapi_get_tank_overflow(network: str, tank: str) -> str | None: - ps = get_tank(network, tank) - return ps['overflow'] - -@app.get("/gettankx/") -async def fastapi_get_tank_x(network: str, tank: str) -> float: - ps = get_tank(network, tank) - return ps['x'] - -@app.get("/gettanky/") -async def fastapi_get_tank_x(network: str, tank: str) -> float: - ps = get_tank(network, tank) - return ps['y'] - -@app.get("/gettankcoord/") -async def fastapi_get_tank_coord(network: str, tank: str) -> dict[str, float]: - ps = get_tank(network, tank) - coord = { 'x' : ps['x'], - 'y' : ps['y'] } - return coord - -@app.post("/settankelevation/",response_model=None) -async def fastapi_set_tank_elevation(network: str, tank: str, elevation: float) -> ChangeSet: - ps = { 'id' : tank, - 'elevation' : elevation } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankinitlevel/",response_model=None) -async def fastapi_set_tank_init_level(network: str, tank: str, init_level: float) -> ChangeSet: - ps = { 'id' : tank, - 'init_level' : init_level } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankminlevel/",response_model=None) -async def fastapi_set_tank_min_level(network: str, tank: str, min_level: float) -> ChangeSet: - ps = { 'id' : tank, - 'min_level' : min_level } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankmaxlevel/",response_model=None) -async def fastapi_set_tank_max_level(network: str, tank: str, max_level: float) -> ChangeSet: - ps = { 'id' : tank, - 'max_level' : max_level } - return set_tank(network, ChangeSet(ps)) - -@app.post("settankdiameter//",response_model=None) -async def fastapi_set_tank_diameter(network: str, tank: str, diameter: float) -> ChangeSet: - ps = { 'id' : tank, - 'diameter' : diameter } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankminvol/",response_model=None) -async def fastapi_set_tank_min_vol(network: str, tank: str, min_vol: float) -> ChangeSet: - ps = { 'id' : tank, - 'min_vol' : min_vol } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankvolcurve/",response_model=None) -async def fastapi_set_tank_vol_curve(network: str, tank: str, vol_curve: str) -> ChangeSet: - ps = { 'id' : tank, - 'vol_curve' : vol_curve} - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankoverflow/",response_model=None) -async def fastapi_set_tank_overflow(network: str, tank: str, overflow: str) -> ChangeSet: - ps = { 'id' : tank, - 'overflow' : overflow } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankx/",response_model=None) -async def fastapi_set_tank_x(network: str, tank: str, x: float) -> ChangeSet: - ps = { 'id' : tank, - 'x' : x } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settanky/",response_model=None) -async def fastapi_set_tank_y(network: str, tank: str, y: float) -> ChangeSet: - ps = { 'id' : tank, - 'y' : y } - return set_tank(network, ChangeSet(ps)) - -@app.post("/settankcoord/",response_model=None) -async def fastapi_set_tank_coord(network: str, tank: str, x: float, y: float) -> ChangeSet: - ps = { 'id' : tank, - 'x' : x, - 'y' : y } - return set_tank(network, ChangeSet(ps)) - -@app.get("/gettankproperties/") -async def fastapi_get_tank_properties(network: str, tank: str) -> dict[str, Any]: - return get_tank(network, tank) - -@app.post("/settankproperties/",response_model=None) -async def fastapi_set_tank_properties(network: str, tank: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : tank } | props - return set_tank(network, ChangeSet(ps)) - -############################################################ -# pipe 4.[PIPES] -############################################################ -@app.get('/getpipeschema') -async def fastapi_get_pipe_schema(network: str) -> dict[str, dict[str, Any]]: - return get_pipe_schema(network) - -@app.post("/addpipe/",response_model=None) -async def fastapi_add_pipe(network: str, pipe: str, node1: str, node2: str, length: float = 0, - diameter: float = 0, roughness: float = 0, minor_loss: float = 0, status: str = PIPE_STATUS_OPEN) -> ChangeSet: - ps = { 'id' : pipe, - 'node1' : node1, - 'node2' : node2, - 'length' : length, - 'diameter' : diameter, - 'roughness' : roughness, - 'minor_loss' : minor_loss, - 'status' : status } - return add_pipe(network, ChangeSet(ps)) - -@app.post("/deletepipe/",response_model=None) -async def fastapi_delete_pipe(network: str, pipe: str) -> ChangeSet: - ps = {'id' : pipe} - return delete_pipe(network, ChangeSet(ps)) - -@app.get("/getpipenode1/") -async def fastapi_get_pipe_node1(network: str, pipe: str) -> str | None: - ps = get_pipe(network, pipe) - return ps['node1'] - -@app.get("/getpipenode2/") -async def fastapi_get_pipe_node2(network: str, pipe: str) -> str | None: - ps = get_pipe(network, pipe) - return ps['node2'] - -@app.get("/getpipelength/") -async def fastapi_get_pipe_length(network: str, pipe: str) -> float | None: - ps = get_pipe(network, pipe) - return ps['length'] - -@app.get("/getpipediameter/") -async def fastapi_get_pipe_diameter(network: str, pipe: str) -> float | None: - ps = get_pipe(network, pipe) - return ps['diameter'] - -@app.get("/getpiperoughness/") -async def fastapi_get_pipe_roughness(network: str, pipe: str) -> float | None: - ps = get_pipe(network, pipe) - return ps['roughness'] - -@app.get("/getpipeminorloss/") -async def fastapi_get_pipe_minor_loss(network: str, pipe: str) -> float | None: - ps = get_pipe(network, pipe) - return ps['minor_loss'] - -@app.get("/getpipestatus/") -async def fastapi_get_pipe_status(network: str, pipe: str) -> str | None: - ps = get_pipe(network, pipe) - return ps['status'] - -@app.post("/setpipenode1/",response_model=None) -async def fastapi_set_pipe_node1(network: str, pipe: str, node1: str) -> ChangeSet: - ps = { 'id' : pipe, - 'node1' : node1 } - return set_pipe(network, ChangeSet(ps)) - -@app.post("/setpipenode2/",response_model=None) -async def fastapi_set_pipe_node2(network: str, pipe: str, node2: str) -> ChangeSet: - ps = { 'id' : pipe, - 'node2' : node2 } - return set_pipe(network, ChangeSet(ps)) - -@app.post("/setpipelength/",response_model=None) -async def fastapi_set_pipe_length(network: str, pipe: str, length: float) -> ChangeSet: - ps = { 'id' : pipe, - 'length' : length } - return set_pipe(network, ChangeSet(ps)) - -@app.post("/setpipediameter/",response_model=None) -async def fastapi_set_pipe_diameter(network: str, pipe: str, diameter: float) -> ChangeSet: - ps = { 'id' : pipe, - 'diameter' : diameter } - return set_pipe(network, ChangeSet(ps)) - -@app.post("/setpiperoughness/",response_model=None) -async def fastapi_set_pipe_roughness(network: str, pipe: str, roughness: float) -> ChangeSet: - ps = { 'id' : pipe, - 'roughness' : roughness } - return set_pipe(network, ChangeSet(ps)) - -@app.post("/setpipeminorloss/",response_model=None) -async def fastapi_set_pipe_minor_loss(network: str, pipe: str, minor_loss: float) -> ChangeSet: - ps = { 'id' : pipe, - 'minor_loss' : minor_loss } - return set_pipe(network, ChangeSet(ps)) - -@app.post("/setpipestatus/",response_model=None) -async def fastapi_set_pipe_status(network: str, pipe: str, status: str) -> ChangeSet: - ps = { 'id' : pipe, - 'status' : status } - - print(status) - print(ps) - - ret = set_pipe(network, ChangeSet(ps)) - print(ret) - return ret - -@app.get("/getpipeproperties/") -async def fastapi_get_pipe_properties(network: str, pipe: str) -> dict[str, Any]: - return get_pipe(network, pipe) - -@app.post("/setpipeproperties/",response_model=None) -async def fastapi_set_pipe_properties(network: str, pipe: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : pipe } | props - return set_pipe(network, ChangeSet(ps)) - - -############################################################ -# pump 4.[PUMPS] -############################################################ -@app.get('/getpumpschema') -async def fastapi_get_pump_schema(network: str) -> dict[str, dict[str, Any]]: - return get_pump_schema(network) - -@app.post("/addpump/",response_model=None) -async def fastapi_add_pump(network: str, pump: str, node1: str, node2: str, power: float = 0.0) -> ChangeSet: - ps = { 'id' : pump, - 'node1' : node1, - 'node2' : node2, - 'power' : power - } - return add_pump(network, ChangeSet(ps)) - -@app.post("/deletepump/",response_model=None) -async def fastapi_delete_pump(network: str, pump: str) -> ChangeSet: - ps = { 'id' : pump } - return delete_pump(network, ChangeSet(ps)) - -@app.get("/getpumpnode1/") -async def fastapi_get_pump_node1(network: str, pump: str) -> str | None: - ps = get_pump(network, pump) - return ps['node1'] - -@app.get("/getpumpnode2/") -async def fastapi_get_pump_node2(network: str, pump: str) -> str | None: - ps = get_pump(network, pump) - return ps['node2'] - -@app.post("/setpumpnode1/",response_model=None) -async def fastapi_set_pump_node1(network: str, pump: str, node1: str) -> ChangeSet: - ps = { 'id' : pump, - 'node1' : node1 } - return set_pump(network, ChangeSet(ps)) - -@app.post("/setpumpnode2/",response_model=None) -async def fastapi_set_pump_node2(network: str, pump: str, node2: str) -> ChangeSet: - ps = { 'id' : pump, - 'node2' : node2 } - return set_pump(network, ChangeSet(ps)) - -@app.get("/getpumpproperties/") -async def fastapi_get_pump_properties(network: str, pump: str) -> dict[str, Any]: - return get_pump(network, pump) - -@app.post("/setpumpproperties/",response_model=None) -async def fastapi_set_pump_properties(network: str, pump: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : pump } | props - return set_pump(network, ChangeSet(ps)) - - -############################################################ -# valve 4.[VALVES] -############################################################ -@app.get('/getvalveschema') -async def fastapi_get_valve_schema(network: str) -> dict[str, dict[str, Any]]: - return get_valve_schema(network) - -@app.post("/addvalve/",response_model=None) -async def fastapi_add_valve(network: str, valve: str, node1: str, node2: str, diameter: float = 0, v_type: str = VALVES_TYPE_PRV, setting: float = 0, minor_loss: float = 0) -> ChangeSet: - ps = { 'id' : valve, - 'node1' : node1, - 'node2' : node2, - 'diameter' : diameter, - 'v_type' : v_type, - 'setting' : setting, - 'minor_loss' : minor_loss } - - return add_valve(network, ChangeSet(ps)) - -@app.post("/deletevalve/",response_model=None) -async def fastapi_delete_valve(network: str, valve: str) -> ChangeSet: - ps = { 'id' : valve } - return delete_valve(network, ChangeSet(ps)) - -@app.get("/getvalvenode1/") -async def fastapi_get_valve_node1(network: str, valve: str) -> str | None: - ps = get_valve(network, valve) - return ps['node1'] - -@app.get("/getvalvenode2/") -async def fastapi_get_valve_node2(network: str, valve: str) -> str | None: - ps = get_valve(network, valve) - return ps['node2'] - -@app.get("/getvalvediameter/") -async def fastapi_get_valve_diameter(network: str, valve: str) -> float | None: - ps = get_valve(network, valve) - return ps['diameter'] - -@app.get("/getvalvetype/") -async def fastapi_get_valve_type(network: str, valve: str) -> str | None: - ps = get_valve(network, valve) - return ps['type'] - -@app.get("/getvalvesetting/") -async def fastapi_get_valve_setting(network: str, valve: str) -> float | None: - ps = get_valve(network, valve) - return ps['setting'] - -@app.get("/getvalveminorloss/") -async def fastapi_get_valve_minor_loss(network: str, valve: str) -> float | None: - ps = get_valve(network, valve) - return ps['minor_loss'] - -@app.post("/setvalvenode1/",response_model=None) -async def fastapi_set_valve_node1(network: str, valve: str, node1: str) -> ChangeSet: - ps = { 'id' : valve, - 'node1' : node1 } - return set_valve(network, ChangeSet(ps)) - -@app.post("/setvalvenode2/",response_model=None) -async def fastapi_set_valve_node2(network: str, valve: str, node2: str) -> ChangeSet: - ps = { 'id' : valve, - 'node2' : node2 } - return set_valve(network, ChangeSet(ps)) - -@app.post("/setvalvenodediameter/",response_model=None) -async def fastapi_set_valve_diameter(network: str, valve: str, diameter: float) -> ChangeSet: - ps = { 'id' : valve, - 'diameter' : diameter } - return set_valve(network, ChangeSet(ps)) - -@app.post("/setvalvetype/",response_model=None) -async def fastapi_set_valve_type(network: str, valve: str, type: str) -> ChangeSet: - ps = { 'id' : valve, - 'type' : type } - return set_valve(network, ChangeSet(ps)) - -@app.post("/setvalvesetting/",response_model=None) -async def fastapi_set_valve_setting(network: str, valve: str, setting: float) -> ChangeSet: - ps = { 'id' : valve, - 'setting' : setting } - return set_valve(network, ChangeSet(ps)) - -@app.get("/getvalveproperties/") -async def fastapi_get_valve_properties(network: str, valve: str) -> dict[str, Any]: - return get_valve(network, valve) - -@app.post("/setvalveproperties/",response_model=None) -async def fastapi_set_valve_properties(network: str, valve: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : valve } | props - return set_valve(network, ChangeSet(ps)) - - -# node & link -@app.post("/deletenode/",response_model=None) -async def fastapi_delete_node(network: str, node: str) -> ChangeSet: - ps = {'id' : node} - if is_junction(network, node): - return delete_junction(network, ChangeSet(ps)) - elif is_reservoir(network, node): - return delete_reservoir(network, ChangeSet(ps)) - elif is_tank(network, node): - return delete_tank(network, ChangeSet(ps)) - -@app.post("/deletelink/",response_model=None) -async def fastapi_delete_link(network: str, link: str) -> ChangeSet: - ps = {'id' : link} - if is_pipe(network, link): - return delete_pipe(network, ChangeSet(ps)) - elif is_pump(network, link): - return delete_pump(network, ChangeSet(ps)) - elif is_valve(network, link): - return delete_valve(network, ChangeSet(ps)) - -############################################################ -# tag 8.[TAGS] -############################################################ -# -# TAG_TYPE_NODE = api.TAG_TYPE_NODE -# TAG_TYPE_LINK = api.TAG_TYPE_LINK -# - -@app.get('/gettagschema/') -async def fastapi_get_tag_schema(network: str) -> dict[str, dict[str, Any]]: - return get_tag_schema(network) - -@app.get('/gettag/') -async def fastapi_get_tag(network: str, t_type: str, id: str) -> dict[str, Any]: - return get_tag(network, t_type, id) - -@app.get('/gettags/') -async def fastapi_get_tags(network: str) -> list[dict[str, Any]]: - tags = get_tags(network) - print(tags) - return tags - -# example: -# set_tag(p, ChangeSet({'t_type': TAG_TYPE_NODE, 'id': 'j1', 'tag': 'j1t' })) -# set_tag(p, ChangeSet({'t_type': TAG_TYPE_LINK, 'id': 'p0', 'tag': 'p0t' })) -@app.post('/settag/',response_model=None) -async def fastapi_set_tag(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_tag(network, ChangeSet(props)) - -############################################################ -# demand 9.[DEMANDS] -############################################################ -@app.get('/getdemandschema') -async def fastapi_get_demand_schema(network: str) -> dict[str, dict[str, Any]]: - return get_demand_schema(network) - -@app.get("/getdemandproperties/") -async def fastapi_get_demand_properties(network: str, junction: str) -> dict[str, Any]: - return get_demand(network, junction) - -# example: set_demand(p, ChangeSet({'junction': 'j1', 'demands': [{'demand': 10.0, 'pattern': None, 'category': 'x'}, {'demand': 20.0, 'pattern': None, 'category': None}]})) -@app.post("/setdemandproperties/",response_model=None) -async def fastapi_set_demand_properties(network: str, junction: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'junction' : junction } | props - return set_demand(network, ChangeSet(ps)) - -############################################################ -# status 10.[STATUS] init_status -############################################################ -@app.get('/getstatusschema') -async def fastapi_get_status_schema(network: str) -> dict[str, dict[str, Any]]: - return get_status_schema(network) - -@app.get("/getstatus/") -async def fastapi_get_status(network: str, link: str) -> dict[str, Any]: - return get_status(network, link) - -# example: set_status(p, ChangeSet({'link': 'p0', 'status': LINK_STATUS_OPEN, 'setting': 10.0})) -@app.post("/setstatus/",response_model=None) -async def fastapi_set_status_properties(network: str, link: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'link' : link } | props - return set_status(network, ChangeSet(ps)) - -############################################################ -# pattern 11.[PATTERNS] -############################################################ -@app.get('/getpatternschema') -async def fastapi_get_pattern_schema(network: str) -> dict[str, dict[str, Any]]: - return get_pattern_schema(network) - -@app.post("/addpattern/",response_model=None) -async def fastapi_add_pattern(network: str, pattern: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { - 'id' : pattern, - } | props - return add_pattern(network, ChangeSet(ps)) - -@app.post("/deletepattern/",response_model=None) -async def fastapi_delete_pattern(network: str, pattern: str) -> ChangeSet: - ps = { 'id' : pattern } - return delete_pattern(network, ChangeSet(ps)) - -@app.get("/getpatternproperties/") -async def fastapi_get_pattern_properties(network: str, pattern: str) -> dict[str, Any]: - return get_pattern(network, pattern) - -# example: set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})) -@app.post("/setpatternproperties/",response_model=None) -async def fastapi_set_pattern_properties(network: str, pattern: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : pattern } | props - return set_pattern(network, ChangeSet(ps)) - -############################################################ -# curve 12.[CURVES] -############################################################ -@app.get('/getcurveschema') -async def fastapi_get_curve_schema(network: str) -> dict[str, dict[str, Any]]: - return get_curve_schema(network) - -@app.post("/addcurve/",response_model=None) -async def fastapi_add_curve(network: str, curve: str, req: Request) -> ChangeSet: - props = await req.json() - - print(props) - - ps = { - 'id' : curve, - } | props - - print(ps) - - return add_curve(network, ChangeSet(ps)) - -@app.post("/deletecurve/",response_model=None) -async def fastapi_delete_curve(network: str, curve: str) -> ChangeSet: - ps = { 'id' : curve } - return delete_curve(network, ChangeSet(ps)) - -@app.get("/getcurveproperties/") -async def fastapi_get_curve_properties(network: str, curve: str) -> dict[str, Any]: - return get_curve(network, curve) - -# example: set_curve(p, ChangeSet({'id' : 'c0', 'c_type' : CURVE_TYPE_PUMP, 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) -@app.post("/setcurveproperties/",response_model=None) -async def fastapi_set_curve_properties(network: str, curve: str, req: Request) -> ChangeSet: - props = await req.json() - # c_type放到request中 - ps = { 'id' : curve } | props - return set_curve(network, ChangeSet(ps)) - - -############################################################ -# control 13.[CONTROLS] -############################################################ -@app.get('/getcontrolschema/') -async def fastapi_get_control_schema(network: str) -> dict[str, dict[str, Any]]: - return get_control_schema(network) - -@app.get("/getcontrolproperties/") -async def fastapi_get_control_properties(network: str) -> dict[str, Any]: - return get_control(network) - -# example: set_control(p, ChangeSet({'control': 'x'})) -@app.post("/setcontrolproperties/",response_model=None) -async def fastapi_set_control_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_control(network, ChangeSet(props)) - -############################################################ -# rule 14.[RULES] -############################################################ -@app.get("/getruleschema/") -async def fastapi_get_rule_schema(network: str) -> dict[str, dict[str, Any]]: - return get_rule_schema(network) - -@app.get("/getruleproperties/") -async def fastapi_get_rule_properties(network: str) -> dict[str, Any]: - return get_rule(network) - -# example: set_rule(p, ChangeSet({'rule': 'x'})) -@app.post("/setruleproperties/",response_model=None) -async def fastapi_set_rule_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_rule(network, ChangeSet(props)) - - -############################################################ -# energy 15.[ENERGY] -############################################################ -@app.get("/getenergyschema/") -async def fastapi_get_energy_schema(network: str) -> dict[str, dict[str, Any]]: - return get_energy_schema(network) - -@app.get("/getenergyproperties/") -async def fastapi_get_energy_properties(network: str) -> dict[str, Any]: - return get_energy(network) - -@app.post("/setenergyproperties/",response_model=None) -async def fastapi_set_energy_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_energy(network, ChangeSet(props)) - -@app.get("/getpumpenergyschema/") -async def fastapi_get_pump_energy_schema(network: str) -> dict[str, dict[str, Any]]: - return get_pump_energy_schema(network) - -@app.get("/getpumpenergyproperties//") -async def fastapi_get_pump_energy_proeprties(network: str, pump: str) -> dict[str, Any]: - return get_pump_energy(network, pump) - -@app.get("/setpumpenergyproperties//",response_model=None) -async def fastapi_set_pump_energy_properties(network: str, pump: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'id' : pump } | props - return set_pump_energy(network, ChangeSet(ps)) - -############################################################ -# emitter 16.[EMITTERS] -############################################################ -@app.get('/getemitterschema') -async def fastapi_get_emitter_schema(network: str) -> dict[str, dict[str, Any]]: - return get_emitter_schema(network) - -@app.get("/getemitterproperties/") -async def fastapi_get_emitter_properties(network: str, junction: str) -> dict[str, Any]: - return get_emitter(network, junction) - -# example: set_emitter(p, ChangeSet({'junction': 'j1', 'coefficient': 10.0})) -@app.post("/setemitterproperties/",response_model=None) -async def fastapi_set_emitter_properties(network: str, junction: str, req: Request) -> ChangeSet: - props = await req.json() - ps = { 'junction' : junction } | props - return set_emitter(network, ChangeSet(ps)) - - -############################################################ -# quality 17.[QUALITY] -############################################################ -@app.get('/getqualityschema/') -async def fastapi_get_quality_schema(network: str) -> dict[str, dict[str, Any]]: - return get_quality_schema(network) - -@app.get('/getqualityproperties/') -async def fastapi_get_quality_properties(network: str, node: str) -> dict[str, Any]: - return get_quality(network, node) - -# example: set_quality(p, ChangeSet({'node': 'j1', 'quality': 10.0})) -@app.post("/setqualityproperties/",response_model=None) -async def fastapi_set_quality_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_quality(network, ChangeSet(props)) - - -############################################################ -# source 18.[SOURCES] -############################################################ -@app.get('/getsourcechema/') -async def fastapi_get_source_schema(network: str) -> dict[str, dict[str, Any]]: - return get_source_schema(network) - -@app.get('/getsource/') -async def fastapi_get_source(network: str, node: str) -> dict[str, Any]: - return get_source(network, node) - -@app.post('/setsource/',response_model=None) -async def fastapi_set_source(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_source(network, ChangeSet(props)) - -# example: add_source(p, ChangeSet({'node': 'j0', 's_type': SOURCE_TYPE_CONCEN, 'strength': 10.0, 'pattern': 'p0'})) -@app.post('/addsource/',response_model=None) -async def fastapi_add_source(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_source(network, ChangeSet(props)) - -@app.post('/deletesource/',response_model=None) -async def fastapi_delete_source(network: str, node: str) -> ChangeSet: - props = { 'node': node } - return delete_source(network, ChangeSet(props)) - - -############################################################ -# reaction 19.[REACTIONS] -############################################################ -@app.get('/getreactionschema/') -async def fastapi_get_reaction_schema(network: str) -> dict[str, dict[str, Any]]: - return get_reaction_schema(network) - -@app.get('/getreaction/') -async def fastapi_get_reaction(network: str) -> dict[str, Any]: - return get_reaction(network) - -@app.post('/setreaction/',response_model=None) -# set_reaction(p, ChangeSet({ 'ORDER BULK' : '10' })) -async def fastapi_set_reaction(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_reaction(network, ChangeSet(props)) - -@app.get('/getpipereactionschema/') -async def fastapi_get_pipe_reaction_schema(network: str) -> dict[str, dict[str, Any]]: - return get_pipe_reaction_schema(network) - -@app.get('/getpipereaction/') -async def fastapi_get_pipe_reaction(network: str, pipe: str) -> dict[str, Any]: - return get_pipe_reaction(network, pipe) - -@app.post('/setpipereaction/',response_model=None) -async def fastapi_set_pipe_reaction(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_pipe_reaction(network, ChangeSet(props)) - -@app.get('/gettankreactionschema/') -async def fastapi_get_tank_reaction_schema(network: str) -> dict[str, dict[str, Any]]: - return get_tank_reaction_schema(network) - -@app.get('/gettankreaction/') -async def fastapi_get_tank_reaction(network: str, tank: str) -> dict[str, Any]: - return get_tank_reaction(network, tank) - -@app.post('/settankreaction/',response_model=None) -async def fastapi_set_tank_reaction(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_tank_reaction(network, ChangeSet(props)) - - -############################################################ -# mixing 20.[MIXING] -############################################################ -@app.get('/getmixingschema/') -async def fastapi_get_mixing_schema(network: str) -> dict[str, dict[str, Any]]: - return get_mixing_schema(network) - -@app.get('/getmixing/') -async def fastapi_get_mixing(network: str, tank: str) -> dict[str, Any]: - return get_mixing(network, tank) - -@app.post('/setmixing/',response_model=None) -async def fastapi_set_mixing(network: str, req: Request) -> ChangeSet: - props = await req.json() - return api.set_mixing(network, ChangeSet(props)) - -# example: add_mixing(p, ChangeSet({'tank': 't0', 'model': MIXING_MODEL_MIXED, 'value': 10.0})) -@app.post('/addmixing/',response_model=None) -async def fastapi_add_mixing(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_mixing(network, ChangeSet(props)) - -@app.post('/deletemixing/',response_model=None) -async def fastapi_delete_mixing(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_mixing(network, ChangeSet(props)) - - -############################################################ -# time 21.[TIME] -############################################################ -@app.get('/gettimeschema') -async def fastapi_get_time_schema(network: str) -> dict[str, dict[str, Any]]: - return get_time_schema(network) - -@app.get("/gettimeproperties/") -async def fastapi_get_time_properties(network: str) -> dict[str, Any]: - return get_time(network) - -@app.post("/settimeproperties/",response_model=None) -async def fastapi_set_time_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_time(network, ChangeSet(props)) - -############################################################ -# option 23.[OPTIONS] -############################################################ -@app.get('/getoptionschema/') -async def fastapi_get_option_schema(network: str) -> dict[str, dict[str, Any]]: - return get_option_v3_schema(network) - -@app.get("/getoptionproperties/") -async def fastapi_get_option_properties(network: str) -> dict[str, Any]: - return get_option_v3(network) - -@app.post("/setoptionproperties/",response_model=None) -async def fastapi_set_option_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_option_v3(network, ChangeSet(props)) - -############################################################ -# coord 24.[COORDINATES] -############################################################ -@app.get("/getnodecoord/") -async def fastapi_get_node_coord(network: str, node: str) -> dict[str, float] | None: - return get_node_coord(network, node) - -############################################################ -# vertex 25.[VERTICES] -############################################################ -@app.get('/getvertexschema/') -async def fastapi_get_vertex_schema(network: str) -> dict[str, dict[str, Any]]: - return get_vertex_schema(network) - -@app.get('/getvertexproperties/') -async def fastapi_get_vertex_properties(network: str, link: str) -> dict[str, Any]: - return get_vertex(network, link) - -# set_vertex(p, ChangeSet({'link' : 'p0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})) -@app.post('/setvertexproperties/',response_model=None) -async def fastapi_set_vertex_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_vertex(network, ChangeSet(props)) - -@app.post('/addvertex/',response_model=None) -async def fastapi_add_vertex(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_vertex(network, ChangeSet(props)) - -@app.post('/deletevertex/',response_model=None) -async def fastapi_delete_vertex(network: str, req: Request) -> ChangeSet: - props = await req.json() - return api.delete_vertex(network, ChangeSet(props)) - -@app.get('/getallvertexlinks/', response_class = PlainTextResponse) -async def fastapi_get_all_vertex_links(network: str) -> list[str]: - return json.dumps(get_all_vertex_links(network)) - -@app.get('/getallvertices/', response_class = PlainTextResponse) -async def fastapi_get_all_vertices(network: str) -> list[dict[str, Any]]: - return json.dumps(get_all_vertices(network)) - -############################################################ -# label 26.[LABELS] -############################################################ -@app.get('/getlabelschema/') -async def fastapi_get_label_schema(network: str) -> dict[str, dict[str, Any]]: - return get_label_schema(network) - -@app.get('/getlabelproperties/') -async def fastapi_get_label_properties(network: str, x: float, y: float) -> dict[str, Any]: - return get_label(network, x, y) - -@app.post('/setlabelproperties/',response_model=None) -async def fastapi_set_label_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_label(network, ChangeSet(props)) - -@app.post('/addlabel/',response_model=None) -async def fastapi_add_label(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_label(network, ChangeSet(props)) - -@app.post('/deletelabel/',response_model=None) -async def fastapi_delete_label(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_label(network, ChangeSet(props)) - - -############################################################ -# backdrop 27.[BACKDROP] -############################################################ -@app.get('/getbackdropschema/') -async def fastapi_get_backdrop_schema(network: str) -> dict[str, dict[str, Any]]: - return get_backdrop_schema(network) - -@app.get('/getbackdropproperties/') -async def fastapi_get_backdrop_properties(network: str) -> dict[str, Any]: - return get_backdrop(network) - -@app.post('/setbackdropproperties/',response_model=None) -async def fastapi_set_backdrop_properties(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_backdrop(network, ChangeSet(props)) - -############################################################ -# scada_device 29 -############################################################ -@app.get('/getscadadeviceschema/') -async def fastapi_get_scada_device_schema(network: str) -> dict[str, dict[str, Any]]: - return get_scada_device_schema(network) - -@app.get('/getscadadevice/') -async def fastapi_get_scada_device(network: str, id: str) -> dict[str, Any]: - return get_scada_device(network, id) - -@app.post('/setscadadevice/',response_model=None) -async def fastapi_set_scada_device(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_scada_device(network, ChangeSet(props)) - -@app.post('/addscadadevice/',response_model=None) -async def fastapi_add_scada_device(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_scada_device(network, ChangeSet(props)) - -@app.post('/deletescadadevice/',response_model=None) -async def fastapi_delete_scada_device(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_scada_device(network, ChangeSet(props)) - -@app.post('/cleanscadadevice/',response_model=None) -async def fastapi_clean_scada_device(network: str) -> ChangeSet: - return clean_scada_device(network) - -@app.get('/getallscadadeviceids/') -async def fastapi_get_all_scada_device_ids(network: str) -> list[str]: - return get_all_scada_device_ids(network) - -@app.get('/getallscadadevices/', response_class = PlainTextResponse) -async def fastapi_get_all_scada_devices(network: str) -> list[dict[str, Any]]: - return json.dumps(get_all_scada_devices(network)) - - -############################################################ -# scada_device_data 30 -############################################################ -@app.get('/getscadadevicedataschema/') -async def fastapi_get_scada_device_data_schema(network: str) -> dict[str, dict[str, Any]]: - return get_scada_device_data_schema(network) - -@app.get('/getscadadevicedata/') -async def fastapi_get_scada_device_data(network: str, id: str) -> dict[str, Any]: - return get_scada_device_data(network, id) - -# example: set_scada_device_data(p, ChangeSet({'device_id': 'sm_device', 'data': [{ 'time': '2023-02-10 00:02:22', 'value': 100.0 }, { 'time': '2023-02-10 00:03:22', 'value': 200.0 }]})) -# time format must be 'YYYY-MM-DD HH:MM:SS' -@app.post('/setscadadevicedata/',response_model=None) -async def fastapi_set_scada_device_data(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_scada_device_data(network, ChangeSet(props)) - -# example: add_scada_device_data(p, ChangeSet({'device_id': 'sm_device', 'time': '2023-02-10 00:02:22', 'value': 100.0})) -@app.post('/addscadadevicedata/',response_model=None) -async def fastapi_add_scada_device_data(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_scada_device_data(network, ChangeSet(props)) - -# example: delete_scada_device_data(p, ChangeSet({'device_id': 'sm_device', 'time': '2023-02-12 00:02:22'})) -@app.post('/deletescadadevicedata/',response_model=None) -async def fastapi_delete_scada_device_data(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_scada_device_data(network, ChangeSet(props)) - -@app.post('/cleanscadadevicedata/',response_model=None) -async def fastapi_clean_scada_device_data(network: str) -> ChangeSet: - return clean_scada_device_data(network) - - -############################################################ -# scada_element 31 -############################################################ -@app.get('/getscadaelementschema/') -async def fastapi_get_scada_element_schema(network: str) -> dict[str, dict[str, Any]]: - return get_scada_element_schema(network) - -@app.get('/getscadaelements/') -async def fastapi_get_scada_elements(network: str) -> list[str]: - return get_scada_elements(network) - -@app.get('/getscadaelement/') -async def fastapi_get_scada_element(network: str, id: str) -> dict[str, Any]: - return get_scada_element(network, id) - -@app.post('/setscadaelement/',response_model=None) -async def fastapi_set_scada_element(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_scada_element(network, ChangeSet(props)) - -@app.post('/addscadaelement/',response_model=None) -async def fastapi_add_scada_element(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_scada_element(network, ChangeSet(props)) - -@app.post('/deletescadaelement/',response_model=None) -async def fastapi_delete_scada_element(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_scada_element(network, ChangeSet(props)) - -@app.post('/cleanscadaelement/',response_model=None) -async def fastapi_clean_scada_element(network: str) -> ChangeSet: - return clean_scada_element(network) - -############################################################ -# general_region 32 -############################################################ -@app.get('/getregionschema/') -async def fastapi_get_region_schema(network: str) -> dict[str, dict[str, Any]]: - return get_region_schema(network) - -@app.get('/getregion/') -async def fastapi_get_region(network: str, id: str) -> dict[str, Any]: - return get_region(network, id) - -@app.post('/setregion/',response_model=None) -async def fastapi_set_region(network : str, req: Request) -> ChangeSet: - props = await req.json() - return set_region(network, ChangeSet(props)) - -# example: add_region(p, ChangeSet({'id': 'r', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]})) -@app.post('/addregion/',response_model=None) -async def fastapi_add_region(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_region(network, ChangeSet(props)) - -@app.post('/deleteregion/',response_model=None) -async def fastapi_delete_region(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_region(network, ChangeSet(props)) - -############################################################ -# district_metering_area 33 -############################################################ -@app.get('/calculatedistrictmeteringareafornodes/') -async def fastapi_calculate_district_metering_area_for_nodes(network: str, req: Request) -> list[list[str]]: - props = await req.json() - nodes = props['nodes'] - part_count = props['part_count'] - part_type = props['part_type'] - return calculate_district_metering_area_for_nodes(network, nodes, part_count, part_type) - -@app.get('/calculatedistrictmeteringareaforregion/') -async def fastapi_calculate_district_metering_area_for_region(network: str, req: Request) -> list[list[str]]: - props = await req.json() - region = props['region'] - part_count = props['part_count'] - part_type = props['part_type'] - return calculate_district_metering_area_for_region(network, region, part_count, part_type) - -@app.get('/calculatedistrictmeteringareafornetwork/') -async def fastapi_calculate_district_metering_area_for_network(network: str, req: Request) -> list[list[str]]: - props = await req.json() - part_count = props['part_count'] - part_type = props['part_type'] - return calculate_district_metering_area_for_network(network, part_count, part_type) - -@app.get('/getdistrictmeteringareaschema/') -async def fastapi_get_district_metering_area_schema(network: str) -> dict[str, dict[str, Any]]: - return get_district_metering_area_schema(network) - -@app.get('/getdistrictmeteringarea/') -async def fastapi_get_district_metering_area(network: str, id: str) -> dict[str, Any]: - return get_district_metering_area(network, id) - -@app.post('/setdistrictmeteringarea/',response_model=None) -async def fastapi_set_district_metering_area(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_district_metering_area(network, ChangeSet(props)) - -@app.post('/adddistrictmeteringarea/',response_model=None) -async def fastapi_add_district_metering_area(network: str, req: Request) -> ChangeSet: - props = await req.json() - -# boundary should be [(x,y), (x,y)] - boundary = props['boundary'] - newBoundary = [] - for pt in boundary: - newBoundary.append((pt[0], pt[1])) - - props['boundary'] = newBoundary - - return add_district_metering_area(network, ChangeSet(props)) - -@app.post('/deletedistrictmeteringarea/',response_model=None) -async def fastapi_delete_district_metering_area(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_district_metering_area(network, ChangeSet(props)) - -@app.get('/getalldistrictmeteringareaids/') -async def fastapi_get_all_district_metering_area_ids(network: str) -> list[str]: - return get_all_district_metering_area_ids(network) - -@app.get('/getalldistrictmeteringareas/') -async def getalldistrictmeteringareas(network: str) -> list[dict[str, Any]]: - return get_all_district_metering_areas(network) - -@app.post('/generatedistrictmeteringarea/',response_model=None) -async def fastapi_generate_district_metering_area(network: str, part_count: int, part_type: int, inflate_delta: float) -> ChangeSet: - return generate_district_metering_area(network, part_count, part_type, inflate_delta) - -@app.post('/generatesubdistrictmeteringarea/',response_model=None) -async def fastapi_generate_sub_district_metering_area(network: str, dma: str, part_count: int, part_type: int, inflate_delta: float) -> ChangeSet: - print(network) - print(dma) - print(part_count) - print(part_type) - print(inflate_delta) - return generate_sub_district_metering_area(network, dma, part_count, part_type, inflate_delta) - -############################################################ -# service_area 34 -############################################################ -@app.get('/calculateservicearea/') -async def fastapi_calculate_service_area(network: str, time_index: int) -> dict[str, Any]: - return calculate_service_area(network, time_index) - -@app.get('/getserviceareaschema/') -async def fastapi_get_service_area_schema(network: str) -> dict[str, dict[str, Any]]: - return get_service_area_schema(network) - -@app.get('/getservicearea/') -async def fastapi_get_service_area(network: str, id: str) -> dict[str, Any]: - return get_service_area(network, id) - -@app.post('/setservicearea/',response_model=None) -async def fastapi_set_service_area(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_service_area(network, ChangeSet(props)) - -@app.post('/addservicearea/',response_model=None) -async def fastapi_add_service_area(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_service_area(network, ChangeSet(props)) - -@app.post('/deleteservicearea/',response_model=None) -async def fastapi_delete_service_area(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_service_area(network, ChangeSet(props)) - -@app.get('/getallserviceareas/') -async def fastapi_get_all_service_areas(network: str) -> list[dict[str, Any]]: - return get_all_service_areas(network) - -@app.post('/generateservicearea/',response_model=None) -async def fastapi_generate_service_area(network: str, inflate_delta: float) -> ChangeSet: - return generate_service_area(network, inflate_delta) - - -############################################################ -# virtual_district 35 -############################################################ -@app.get('/calculatevirtualdistrict/') -async def fastapi_calculate_virtual_district(network: str, centers: list[str]) -> dict[str, list[Any]]: - return calculate_virtual_district(network, centers) - -@app.get('/getvirtualdistrictschema/') -async def fastapi_get_virtual_district_schema(network: str) -> dict[str, dict[str, Any]]: - return get_virtual_district_schema(network) - -@app.get('/getvirtualdistrict/') -async def fastapi_get_virtual_district(network: str, id: str) -> dict[str, Any]: - return get_virtual_district(network, id) - -@app.post('/setvirtualdistrict/',response_model=None) -async def fastapi_set_virtual_district(network: str, req: Request) -> ChangeSet: - props = await req.json() - return set_virtual_district(network, ChangeSet(props)) - -@app.post('/addvirtualdistrict/',response_model=None) -async def fastapi_add_virtual_district(network: str, req: Request) -> ChangeSet: - props = await req.json() - return add_virtual_district(network, ChangeSet(props)) - -@app.post('/deletevirtualdistrict/',response_model=None) -async def fastapi_delete_virtual_district(network: str, req: Request) -> ChangeSet: - props = await req.json() - return delete_virtual_district(network, ChangeSet(props)) - -@app.get('/getallvirtualdistrict/') -async def fastapi_get_all_virtual_district(network: str) -> list[dict[str, Any]]: - return get_all_virtual_districts(network) - -@app.post('/generatevirtualdistrict/',response_model=None) -async def fastapi_generate_virtual_district(network: str, inflate_delta: float, req: Request) -> ChangeSet: - props = await req.json() - return generate_virtual_district(network, props['centers'], inflate_delta) - -############################################################ -# water_distribution_area 36 -############################################################ -@app.get('/calculatedemandtonodes/') -async def fastapi_calculate_demand_to_nodes(network: str, req: Request) -> dict[str, float]: - props = await req.json() - demand = props['demand'] - nodes = props['nodes'] - return calculate_demand_to_nodes(network, demand, nodes) - -@app.get('/calculatedemandtoregion/') -async def fastapi_calculate_demand_to_region(network: str, req: Request) -> dict[str, float]: - props = await req.json() - demand = props['demand'] - region = props['region'] - return calculate_demand_to_region(network, demand, region) - -@app.get('/calculatedemandtonetwork/') -async def fastapi_calculate_demand_to_network(network: str, demand: float) -> dict[str, float]: - return calculate_demand_to_network(network, demand) - - - -# inp file -#@app.post("/uploadinp/", status_code=status.HTTP_200_OK) -#async def upload_inp(afile: bytes, name: str ): - #filePath = inpDir + str(name) - #f = open(filePath, 'wb') - #f.write(afile) - #f.close() - - #return True - -@app.get("/downloadinp/", status_code=status.HTTP_200_OK) -async def download_inp(name: str, response: Response): - filePath = inpDir + name - if os.path.exists(filePath): - return FileResponse(filePath, media_type='application/octet-stream', filename="inp.inp") - else: - response.status_code = status.HTTP_400_BAD_REQUEST - return True - -@app.get("/getjson/") -async def get_json(): - return JSONResponse( - status_code = status.HTTP_400_BAD_REQUEST, - content={ - 'code': 400, - 'message': "this is message", - 'data': 123, - } - ) - - diff --git a/openapi.json b/openapi.json deleted file mode 100644 index 12c864f..0000000 --- a/openapi.json +++ /dev/null @@ -1,13577 +0,0 @@ -{ - "openapi": "3.0.2", - "info": { - "title": "FastAPI", - "version": "0.1.0" - }, - "paths": { - "/getallextensiondatakeys/": { - "get": { - "summary": "Fastapi Get All Extension Data Keys", - "operationId": "fastapi_get_all_extension_data_keys_getallextensiondatakeys__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getallextensiondata/": { - "get": { - "summary": "Fastapi Get All Extension Data", - "operationId": "fastapi_get_all_extension_data_getallextensiondata__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getextensiondata/": { - "get": { - "summary": "Fastapi Get Extension Data", - "operationId": "fastapi_get_extension_data_getextensiondata__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Key", - "type": "string" - }, - "name": "key", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setextensiondata": { - "post": { - "summary": "Fastapi Set Extension Data", - "operationId": "fastapi_set_extension_data_setextensiondata_post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/listprojects/": { - "get": { - "summary": "Fastapi List Projects", - "operationId": "fastapi_list_projects_listprojects__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - } - } - } - }, - "/haveproject/": { - "get": { - "summary": "Fastapi Have Project", - "operationId": "fastapi_have_project_haveproject__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/createproject/": { - "post": { - "summary": "Fastapi Create Project", - "operationId": "fastapi_create_project_createproject__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deleteproject/": { - "post": { - "summary": "Fastapi Delete Project", - "operationId": "fastapi_delete_project_deleteproject__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/isprojectopen/": { - "get": { - "summary": "Fastapi Is Project Open", - "operationId": "fastapi_is_project_open_isprojectopen__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/openproject/": { - "post": { - "summary": "Fastapi Open Project", - "operationId": "fastapi_open_project_openproject__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/closeproject/": { - "post": { - "summary": "Fastapi Close Project", - "operationId": "fastapi_close_project_closeproject__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/copyproject/": { - "post": { - "summary": "Fastapi Copy Project", - "operationId": "fastapi_copy_project_copyproject__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Source", - "type": "string" - }, - "name": "source", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Target", - "type": "string" - }, - "name": "target", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/importinp/": { - "post": { - "summary": "Fastapi Import Inp", - "operationId": "fastapi_import_inp_importinp__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/exportinp/": { - "get": { - "summary": "Fastapi Export Inp", - "operationId": "fastapi_export_inp_exportinp__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Version", - "type": "string" - }, - "name": "version", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/readinp/": { - "post": { - "summary": "Fastapi Read Inp", - "operationId": "fastapi_read_inp_readinp__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Inp", - "type": "string" - }, - "name": "inp", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/dumpinp/": { - "get": { - "summary": "Fastapi Dump Inp", - "operationId": "fastapi_dump_inp_dumpinp__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Inp", - "type": "string" - }, - "name": "inp", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/runproject/": { - "get": { - "summary": "Fastapi Run Project", - "operationId": "fastapi_run_project_runproject__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/runinp/": { - "get": { - "summary": "Fastapi Run Inp", - "operationId": "fastapi_run_inp_runinp__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/dumpoutput/": { - "get": { - "summary": "Fastapi Dump Output", - "operationId": "fastapi_dump_output_dumpoutput__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Output", - "type": "string" - }, - "name": "output", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/isprojectlocked/": { - "get": { - "summary": "Fastapi Is Locked", - "operationId": "fastapi_is_locked_isprojectlocked__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/isprojectlockedbyme/": { - "get": { - "summary": "Fastapi Is Locked By Me", - "operationId": "fastapi_is_locked_by_me_isprojectlockedbyme__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/lockproject/": { - "post": { - "summary": "Fastapi Lock Project", - "operationId": "fastapi_lock_project_lockproject__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/unlockproject/": { - "post": { - "summary": "Fastapi Unlock Project", - "operationId": "fastapi_unlock_project_unlockproject__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getcurrentoperationid/": { - "get": { - "summary": "Fastapi Get Current Operaiton Id", - "operationId": "fastapi_get_current_operaiton_id_getcurrentoperationid__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/undo/": { - "post": { - "summary": "Fastapi Undo", - "operationId": "fastapi_undo_undo__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/redo/": { - "post": { - "summary": "Fastapi Redo", - "operationId": "fastapi_redo_redo__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getsnapshots/": { - "get": { - "summary": "Fastapi List Snapshot", - "operationId": "fastapi_list_snapshot_getsnapshots__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/havesnapshot/": { - "get": { - "summary": "Fastapi Have Snapshot", - "operationId": "fastapi_have_snapshot_havesnapshot__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tag", - "type": "string" - }, - "name": "tag", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/havesnapshotforoperation/": { - "get": { - "summary": "Fastapi Have Snapshot For Operation", - "operationId": "fastapi_have_snapshot_for_operation_havesnapshotforoperation__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Operation", - "type": "integer" - }, - "name": "operation", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/havesnapshotforcurrentoperation/": { - "get": { - "summary": "Fastapi Have Snapshot For Current Operation", - "operationId": "fastapi_have_snapshot_for_current_operation_havesnapshotforcurrentoperation__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/takesnapshotforoperation/": { - "post": { - "summary": "Fastapi Take Snapshot For Operation", - "operationId": "fastapi_take_snapshot_for_operation_takesnapshotforoperation__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Operation", - "type": "integer" - }, - "name": "operation", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tag", - "type": "string" - }, - "name": "tag", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "takenapshotforcurrentoperation": { - "post": { - "summary": "Fastapi Take Snapshot For Current Operation", - "operationId": "fastapi_take_snapshot_for_current_operationtakenapshotforcurrentoperation_post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tag", - "type": "string" - }, - "name": "tag", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/takesnapshot/": { - "post": { - "summary": "Fastapi Take Snapshot", - "operationId": "fastapi_take_snapshot_takesnapshot__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tag", - "type": "string" - }, - "name": "tag", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/picksnapshot/": { - "post": { - "summary": "Fastapi Pick Snapshot", - "operationId": "fastapi_pick_snapshot_picksnapshot__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tag", - "type": "string" - }, - "name": "tag", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Discard", - "type": "boolean", - "default": false - }, - "name": "discard", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/pickoperation/": { - "post": { - "summary": "Fastapi Pick Operation", - "operationId": "fastapi_pick_operation_pickoperation__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Operation", - "type": "integer" - }, - "name": "operation", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Discard", - "type": "boolean", - "default": false - }, - "name": "discard", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/syncwithserver/": { - "get": { - "summary": "Fastapi Sync With Server", - "operationId": "fastapi_sync_with_server_syncwithserver__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Operation", - "type": "integer" - }, - "name": "operation", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/batch/": { - "post": { - "summary": "Fastapi Execute Batch Commands", - "operationId": "fastapi_execute_batch_commands_batch__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/compressedbatch/": { - "post": { - "summary": "Fastapi Execute Compressed Batch Commands", - "operationId": "fastapi_execute_compressed_batch_commands_compressedbatch__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getrestoreoperation/": { - "get": { - "summary": "Fastapi Get Restore Operation", - "operationId": "fastapi_get_restore_operation_getrestoreoperation__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setrestoreoperation/": { - "post": { - "summary": "Fastapi Set Restore Operation", - "operationId": "fastapi_set_restore_operation_setrestoreoperation__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Operation", - "type": "integer" - }, - "name": "operation", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/isnode/": { - "get": { - "summary": "Fastapi Is Node", - "operationId": "fastapi_is_node_isnode__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/isjunction/": { - "get": { - "summary": "Fastapi Is Junction", - "operationId": "fastapi_is_junction_isjunction__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/isreservoir/": { - "get": { - "summary": "Fastapi Is Reservoir", - "operationId": "fastapi_is_reservoir_isreservoir__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/istank/": { - "get": { - "summary": "Fastapi Is Tank", - "operationId": "fastapi_is_tank_istank__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/islink/": { - "get": { - "summary": "Fastapi Is Link", - "operationId": "fastapi_is_link_islink__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/ispipe/": { - "get": { - "summary": "Fastapi Is Pipe", - "operationId": "fastapi_is_pipe_ispipe__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/ispump/": { - "get": { - "summary": "Fastapi Is Pump", - "operationId": "fastapi_is_pump_ispump__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/isvalve/": { - "get": { - "summary": "Fastapi Is Valve", - "operationId": "fastapi_is_valve_isvalve__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/iscurve/": { - "get": { - "summary": "Fastapi Is Curve", - "operationId": "fastapi_is_curve_iscurve__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Curve", - "type": "string" - }, - "name": "curve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/ispattern/": { - "get": { - "summary": "Fastapi Is Pattern", - "operationId": "fastapi_is_pattern_ispattern__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pattern", - "type": "string" - }, - "name": "pattern", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getnodes/": { - "get": { - "summary": "Fastapi Get Nodes", - "operationId": "fastapi_get_nodes_getnodes__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getlinks/": { - "get": { - "summary": "Fastapi Get Links", - "operationId": "fastapi_get_links_getlinks__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getcurves/": { - "get": { - "summary": "Fastapi Get Curves", - "operationId": "fastapi_get_curves_getcurves__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpatterns/": { - "get": { - "summary": "Fastapi Get Patterns", - "operationId": "fastapi_get_patterns_getpatterns__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getnodelinks/": { - "get": { - "summary": "Get Node Links", - "operationId": "get_node_links_getnodelinks__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettitleschema/": { - "get": { - "summary": "Fast Get Title Schema", - "operationId": "fast_get_title_schema_gettitleschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettitle/": { - "get": { - "summary": "Fast Get Title", - "operationId": "fast_get_title_gettitle__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settitle/": { - "get": { - "summary": "Fastapi Set Title", - "operationId": "fastapi_set_title_settitle__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctionschema": { - "get": { - "summary": "Fast Get Junction Schema", - "operationId": "fast_get_junction_schema_getjunctionschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addjunction/": { - "post": { - "summary": "Fastapi Add Junction", - "operationId": "fastapi_add_junction_addjunction__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Z", - "type": "number" - }, - "name": "z", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletejunction/": { - "post": { - "summary": "Fastapi Delete Junction", - "operationId": "fastapi_delete_junction_deletejunction__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctionelevation/": { - "get": { - "summary": "Fastapi Get Junction Elevation", - "operationId": "fastapi_get_junction_elevation_getjunctionelevation__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctionx/": { - "get": { - "summary": "Fastapi Get Junction X", - "operationId": "fastapi_get_junction_x_getjunctionx__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctiony/": { - "get": { - "summary": "Fastapi Get Junction X", - "operationId": "fastapi_get_junction_x_getjunctiony__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctioncoord/": { - "get": { - "summary": "Fastapi Get Junction Coord", - "operationId": "fastapi_get_junction_coord_getjunctioncoord__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctiondemand/": { - "get": { - "summary": "Fastapi Get Junction Demand", - "operationId": "fastapi_get_junction_demand_getjunctiondemand__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctionpattern/": { - "get": { - "summary": "Fastapi Get Junction Pattern", - "operationId": "fastapi_get_junction_pattern_getjunctionpattern__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setjunctionelevation/": { - "post": { - "summary": "Fastapi Set Junction Elevation", - "operationId": "fastapi_set_junction_elevation_setjunctionelevation__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Elevation", - "type": "number" - }, - "name": "elevation", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setjunctionx/": { - "post": { - "summary": "Fastapi Set Junction X", - "operationId": "fastapi_set_junction_x_setjunctionx__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setjunctiony/": { - "post": { - "summary": "Fastapi Set Junction Y", - "operationId": "fastapi_set_junction_y_setjunctiony__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setjunctioncoord/": { - "post": { - "summary": "Fastapi Set Junction Coord", - "operationId": "fastapi_set_junction_coord_setjunctioncoord__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setjunctiondemand/": { - "post": { - "summary": "Fastapi Set Junction Demand", - "operationId": "fastapi_set_junction_demand_setjunctiondemand__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Demand", - "type": "number" - }, - "name": "demand", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setjunctionpattern/": { - "post": { - "summary": "Fastapi Set Junction Pattern", - "operationId": "fastapi_set_junction_pattern_setjunctionpattern__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pattern", - "type": "string" - }, - "name": "pattern", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getjunctionproperties/": { - "get": { - "summary": "Fastapi Get Junction Properties", - "operationId": "fastapi_get_junction_properties_getjunctionproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setjunctionproperties/": { - "post": { - "summary": "Fastapi Set Junction Properties", - "operationId": "fastapi_set_junction_properties_setjunctionproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreservoirschema": { - "get": { - "summary": "Fast Get Reservoir Schema", - "operationId": "fast_get_reservoir_schema_getreservoirschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addreservoir/": { - "post": { - "summary": "Fastapi Add Reservoir", - "operationId": "fastapi_add_reservoir_addreservoir__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Head", - "type": "number" - }, - "name": "head", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletereservoir/": { - "post": { - "summary": "Fastapi Delete Reservoir", - "operationId": "fastapi_delete_reservoir_deletereservoir__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreservoirhead/": { - "get": { - "summary": "Fastapi Get Reservoir Head", - "operationId": "fastapi_get_reservoir_head_getreservoirhead__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreservoirpattern/": { - "get": { - "summary": "Fastapi Get Reservoir Pattern", - "operationId": "fastapi_get_reservoir_pattern_getreservoirpattern__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreservoirx/": { - "get": { - "summary": "Fastapi Get Reservoir X", - "operationId": "fastapi_get_reservoir_x_getreservoirx__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreservoiry/": { - "get": { - "summary": "Fastapi Get Reservoir Y", - "operationId": "fastapi_get_reservoir_y_getreservoiry__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreservoircoord/": { - "get": { - "summary": "Fastapi Get Reservoir Y", - "operationId": "fastapi_get_reservoir_y_getreservoircoord__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setreservoirhead/": { - "post": { - "summary": "Fastapi Set Reservoir Head", - "operationId": "fastapi_set_reservoir_head_setreservoirhead__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Head", - "type": "number" - }, - "name": "head", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setreservoirpattern/": { - "post": { - "summary": "Fastapi Set Reservoir Pattern", - "operationId": "fastapi_set_reservoir_pattern_setreservoirpattern__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pattern", - "type": "string" - }, - "name": "pattern", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setreservoirx/": { - "post": { - "summary": "Fastapi Set Reservoir Y", - "operationId": "fastapi_set_reservoir_y_setreservoirx__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setreservoircoord/": { - "post": { - "summary": "Fastapi Set Reservoir Y", - "operationId": "fastapi_set_reservoir_y_setreservoircoord__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreservoirproperties/": { - "get": { - "summary": "Fastapi Get Reservoir Properties", - "operationId": "fastapi_get_reservoir_properties_getreservoirproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setreservoirproperties/": { - "post": { - "summary": "Fastapi Set Reservoir Properties", - "operationId": "fastapi_set_reservoir_properties_setreservoirproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Reservoir", - "type": "string" - }, - "name": "reservoir", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankschema": { - "get": { - "summary": "Fast Get Tank Schema", - "operationId": "fast_get_tank_schema_gettankschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addtank/": { - "post": { - "summary": "Fastapi Add Tank", - "operationId": "fastapi_add_tank_addtank__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Elevation", - "type": "number" - }, - "name": "elevation", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Init Level", - "type": "number", - "default": 0 - }, - "name": "init_level", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Min Level", - "type": "number", - "default": 0 - }, - "name": "min_level", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Max Level", - "type": "number", - "default": 0 - }, - "name": "max_level", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Diameter", - "type": "number", - "default": 0 - }, - "name": "diameter", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Min Vol", - "type": "number", - "default": 0 - }, - "name": "min_vol", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletetank/": { - "post": { - "summary": "Fastapi Delete Tank", - "operationId": "fastapi_delete_tank_deletetank__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankelevation/": { - "get": { - "summary": "Fastapi Get Tank Elevation", - "operationId": "fastapi_get_tank_elevation_gettankelevation__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankinitlevel/": { - "get": { - "summary": "Fastapi Get Tank Init Level", - "operationId": "fastapi_get_tank_init_level_gettankinitlevel__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankminlevel/": { - "get": { - "summary": "Fastapi Get Tank Min Level", - "operationId": "fastapi_get_tank_min_level_gettankminlevel__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankmaxlevel/": { - "get": { - "summary": "Fastapi Get Tank Max Level", - "operationId": "fastapi_get_tank_max_level_gettankmaxlevel__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankdiameter/": { - "get": { - "summary": "Fastapi Get Tank Diameter", - "operationId": "fastapi_get_tank_diameter_gettankdiameter__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankminvol/": { - "get": { - "summary": "Fastapi Get Tank Min Vol", - "operationId": "fastapi_get_tank_min_vol_gettankminvol__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankvolcurve/": { - "get": { - "summary": "Fastapi Get Tank Vol Curve", - "operationId": "fastapi_get_tank_vol_curve_gettankvolcurve__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankoverflow/": { - "get": { - "summary": "Fastapi Get Tank Overflow", - "operationId": "fastapi_get_tank_overflow_gettankoverflow__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankx/": { - "get": { - "summary": "Fastapi Get Tank X", - "operationId": "fastapi_get_tank_x_gettankx__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettanky/": { - "get": { - "summary": "Fastapi Get Tank X", - "operationId": "fastapi_get_tank_x_gettanky__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankcoord/": { - "get": { - "summary": "Fastapi Get Tank Coord", - "operationId": "fastapi_get_tank_coord_gettankcoord__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankelevation/": { - "post": { - "summary": "Fastapi Set Tank Elevation", - "operationId": "fastapi_set_tank_elevation_settankelevation__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Elevation", - "type": "number" - }, - "name": "elevation", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankinitlevel/": { - "post": { - "summary": "Fastapi Set Tank Init Level", - "operationId": "fastapi_set_tank_init_level_settankinitlevel__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Init Level", - "type": "number" - }, - "name": "init_level", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankminlevel/": { - "post": { - "summary": "Fastapi Set Tank Min Level", - "operationId": "fastapi_set_tank_min_level_settankminlevel__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Min Level", - "type": "number" - }, - "name": "min_level", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankmaxlevel/": { - "post": { - "summary": "Fastapi Set Tank Max Level", - "operationId": "fastapi_set_tank_max_level_settankmaxlevel__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Max Level", - "type": "number" - }, - "name": "max_level", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "settankdiameter//": { - "post": { - "summary": "Fastapi Set Tank Diameter", - "operationId": "fastapi_set_tank_diametersettankdiameter___post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Diameter", - "type": "number" - }, - "name": "diameter", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankminvol/": { - "post": { - "summary": "Fastapi Set Tank Min Vol", - "operationId": "fastapi_set_tank_min_vol_settankminvol__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Min Vol", - "type": "number" - }, - "name": "min_vol", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankvolcurve/": { - "post": { - "summary": "Fastapi Set Tank Vol Curve", - "operationId": "fastapi_set_tank_vol_curve_settankvolcurve__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Vol Curve", - "type": "string" - }, - "name": "vol_curve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankoverflow/": { - "post": { - "summary": "Fastapi Set Tank Overflow", - "operationId": "fastapi_set_tank_overflow_settankoverflow__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Overflow", - "type": "string" - }, - "name": "overflow", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankx/": { - "post": { - "summary": "Fastapi Set Tank X", - "operationId": "fastapi_set_tank_x_settankx__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settanky/": { - "post": { - "summary": "Fastapi Set Tank Y", - "operationId": "fastapi_set_tank_y_settanky__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankcoord/": { - "post": { - "summary": "Fastapi Set Tank Coord", - "operationId": "fastapi_set_tank_coord_settankcoord__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankproperties/": { - "get": { - "summary": "Fastapi Get Tank Properties", - "operationId": "fastapi_get_tank_properties_gettankproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankproperties/": { - "post": { - "summary": "Fastapi Set Tank Properties", - "operationId": "fastapi_set_tank_properties_settankproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipeschema": { - "get": { - "summary": "Fastapi Get Pipe Schema", - "operationId": "fastapi_get_pipe_schema_getpipeschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addpipe/": { - "post": { - "summary": "Fastapi Add Pipe", - "operationId": "fastapi_add_pipe_addpipe__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node1", - "type": "string" - }, - "name": "node1", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node2", - "type": "string" - }, - "name": "node2", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Length", - "type": "number", - "default": 0 - }, - "name": "length", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Diameter", - "type": "number", - "default": 0 - }, - "name": "diameter", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Roughness", - "type": "number", - "default": 0 - }, - "name": "roughness", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Minor Loss", - "type": "number", - "default": 0 - }, - "name": "minor_loss", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Status", - "type": "string", - "default": "OPEN" - }, - "name": "status", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletepipe/": { - "post": { - "summary": "Fastapi Delete Pipe", - "operationId": "fastapi_delete_pipe_deletepipe__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipenode1/": { - "get": { - "summary": "Fastapi Get Pipe Node1", - "operationId": "fastapi_get_pipe_node1_getpipenode1__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipenode2/": { - "get": { - "summary": "Fastapi Get Pipe Node2", - "operationId": "fastapi_get_pipe_node2_getpipenode2__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipelength/": { - "get": { - "summary": "Fastapi Get Pipe Length", - "operationId": "fastapi_get_pipe_length_getpipelength__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipediameter/": { - "get": { - "summary": "Fastapi Get Pipe Diameter", - "operationId": "fastapi_get_pipe_diameter_getpipediameter__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpiperoughness/": { - "get": { - "summary": "Fastapi Get Pipe Roughness", - "operationId": "fastapi_get_pipe_roughness_getpiperoughness__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipeminorloss/": { - "get": { - "summary": "Fastapi Get Pipe Minor Loss", - "operationId": "fastapi_get_pipe_minor_loss_getpipeminorloss__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipestatus/": { - "get": { - "summary": "Fastapi Get Pipe Status", - "operationId": "fastapi_get_pipe_status_getpipestatus__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipenode1/": { - "post": { - "summary": "Fastapi Set Pipe Node1", - "operationId": "fastapi_set_pipe_node1_setpipenode1__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node1", - "type": "string" - }, - "name": "node1", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipenode2/": { - "post": { - "summary": "Fastapi Set Pipe Node2", - "operationId": "fastapi_set_pipe_node2_setpipenode2__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node2", - "type": "string" - }, - "name": "node2", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipelength/": { - "post": { - "summary": "Fastapi Set Pipe Length", - "operationId": "fastapi_set_pipe_length_setpipelength__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Length", - "type": "number" - }, - "name": "length", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipediameter/": { - "post": { - "summary": "Fastapi Set Pipe Diameter", - "operationId": "fastapi_set_pipe_diameter_setpipediameter__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Diameter", - "type": "number" - }, - "name": "diameter", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpiperoughness/": { - "post": { - "summary": "Fastapi Set Pipe Roughness", - "operationId": "fastapi_set_pipe_roughness_setpiperoughness__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Roughness", - "type": "number" - }, - "name": "roughness", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipeminorloss/": { - "post": { - "summary": "Fastapi Set Pipe Minor Loss", - "operationId": "fastapi_set_pipe_minor_loss_setpipeminorloss__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Minor Loss", - "type": "number" - }, - "name": "minor_loss", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipestatus/": { - "post": { - "summary": "Fastapi Set Pipe Status", - "operationId": "fastapi_set_pipe_status_setpipestatus__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Status", - "type": "string" - }, - "name": "status", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipeproperties/": { - "get": { - "summary": "Fastapi Get Pipe Properties", - "operationId": "fastapi_get_pipe_properties_getpipeproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipeproperties/": { - "post": { - "summary": "Fastapi Set Pipe Properties", - "operationId": "fastapi_set_pipe_properties_setpipeproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpumpschema": { - "get": { - "summary": "Fastapi Get Pump Schema", - "operationId": "fastapi_get_pump_schema_getpumpschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addpump/": { - "post": { - "summary": "Fastapi Add Pump", - "operationId": "fastapi_add_pump_addpump__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node1", - "type": "string" - }, - "name": "node1", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node2", - "type": "string" - }, - "name": "node2", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Power", - "type": "number", - "default": 0.0 - }, - "name": "power", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletepump/": { - "post": { - "summary": "Fastapi Delete Pump", - "operationId": "fastapi_delete_pump_deletepump__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpumpnode1/": { - "get": { - "summary": "Fastapi Get Pump Node1", - "operationId": "fastapi_get_pump_node1_getpumpnode1__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpumpnode2/": { - "get": { - "summary": "Fastapi Get Pump Node2", - "operationId": "fastapi_get_pump_node2_getpumpnode2__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpumpnode1/": { - "post": { - "summary": "Fastapi Set Pump Node1", - "operationId": "fastapi_set_pump_node1_setpumpnode1__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node1", - "type": "string" - }, - "name": "node1", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpumpnode2/": { - "post": { - "summary": "Fastapi Set Pump Node2", - "operationId": "fastapi_set_pump_node2_setpumpnode2__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node2", - "type": "string" - }, - "name": "node2", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpumpproperties/": { - "get": { - "summary": "Fastapi Get Pump Properties", - "operationId": "fastapi_get_pump_properties_getpumpproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpumpproperties/": { - "post": { - "summary": "Fastapi Set Pump Properties", - "operationId": "fastapi_set_pump_properties_setpumpproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalveschema": { - "get": { - "summary": "Fastapi Get Valve Schema", - "operationId": "fastapi_get_valve_schema_getvalveschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addvalve/": { - "post": { - "summary": "Fastapi Add Valve", - "operationId": "fastapi_add_valve_addvalve__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node1", - "type": "string" - }, - "name": "node1", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node2", - "type": "string" - }, - "name": "node2", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Diameter", - "type": "number", - "default": 0 - }, - "name": "diameter", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "V Type", - "type": "string", - "default": "PRV" - }, - "name": "v_type", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Setting", - "type": "number", - "default": 0 - }, - "name": "setting", - "in": "query" - }, - { - "required": false, - "schema": { - "title": "Minor Loss", - "type": "number", - "default": 0 - }, - "name": "minor_loss", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletevalve/": { - "post": { - "summary": "Fastapi Delete Valve", - "operationId": "fastapi_delete_valve_deletevalve__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalvenode1/": { - "get": { - "summary": "Fastapi Get Valve Node1", - "operationId": "fastapi_get_valve_node1_getvalvenode1__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalvenode2/": { - "get": { - "summary": "Fastapi Get Valve Node2", - "operationId": "fastapi_get_valve_node2_getvalvenode2__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalvediameter/": { - "get": { - "summary": "Fastapi Get Valve Diameter", - "operationId": "fastapi_get_valve_diameter_getvalvediameter__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalvetype/": { - "get": { - "summary": "Fastapi Get Valve Type", - "operationId": "fastapi_get_valve_type_getvalvetype__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalvesetting/": { - "get": { - "summary": "Fastapi Get Valve Setting", - "operationId": "fastapi_get_valve_setting_getvalvesetting__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalveminorloss/": { - "get": { - "summary": "Fastapi Get Valve Minor Loss", - "operationId": "fastapi_get_valve_minor_loss_getvalveminorloss__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvalvenode1/": { - "post": { - "summary": "Fastapi Set Valve Node1", - "operationId": "fastapi_set_valve_node1_setvalvenode1__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node1", - "type": "string" - }, - "name": "node1", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvalvenode2/": { - "post": { - "summary": "Fastapi Set Valve Node2", - "operationId": "fastapi_set_valve_node2_setvalvenode2__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node2", - "type": "string" - }, - "name": "node2", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvalvenodediameter/": { - "post": { - "summary": "Fastapi Set Valve Diameter", - "operationId": "fastapi_set_valve_diameter_setvalvenodediameter__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Diameter", - "type": "number" - }, - "name": "diameter", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvalvetype/": { - "post": { - "summary": "Fastapi Set Valve Type", - "operationId": "fastapi_set_valve_type_setvalvetype__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Type", - "type": "string" - }, - "name": "type", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvalvesetting/": { - "post": { - "summary": "Fastapi Set Valve Setting", - "operationId": "fastapi_set_valve_setting_setvalvesetting__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Setting", - "type": "number" - }, - "name": "setting", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvalveproperties/": { - "get": { - "summary": "Fastapi Get Valve Properties", - "operationId": "fastapi_get_valve_properties_getvalveproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvalveproperties/": { - "post": { - "summary": "Fastapi Set Valve Properties", - "operationId": "fastapi_set_valve_properties_setvalveproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Valve", - "type": "string" - }, - "name": "valve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletenode/": { - "post": { - "summary": "Fastapi Delete Node", - "operationId": "fastapi_delete_node_deletenode__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletelink/": { - "post": { - "summary": "Fastapi Delete Link", - "operationId": "fastapi_delete_link_deletelink__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettagschema/": { - "get": { - "summary": "Fastapi Get Tag Schema", - "operationId": "fastapi_get_tag_schema_gettagschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettag/": { - "get": { - "summary": "Fastapi Get Tag", - "operationId": "fastapi_get_tag_gettag__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "T Type", - "type": "string" - }, - "name": "t_type", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettags/": { - "get": { - "summary": "Fastapi Get Tags", - "operationId": "fastapi_get_tags_gettags__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settag/": { - "post": { - "summary": "Fastapi Set Tag", - "operationId": "fastapi_set_tag_settag__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getdemandschema": { - "get": { - "summary": "Fastapi Get Demand Schema", - "operationId": "fastapi_get_demand_schema_getdemandschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getdemandproperties/": { - "get": { - "summary": "Fastapi Get Demand Properties", - "operationId": "fastapi_get_demand_properties_getdemandproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setdemandproperties/": { - "post": { - "summary": "Fastapi Set Demand Properties", - "operationId": "fastapi_set_demand_properties_setdemandproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getstatusschema": { - "get": { - "summary": "Fastapi Get Status Schema", - "operationId": "fastapi_get_status_schema_getstatusschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getstatus/": { - "get": { - "summary": "Fastapi Get Status", - "operationId": "fastapi_get_status_getstatus__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setstatus/": { - "post": { - "summary": "Fastapi Set Status Properties", - "operationId": "fastapi_set_status_properties_setstatus__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpatternschema": { - "get": { - "summary": "Fastapi Get Pattern Schema", - "operationId": "fastapi_get_pattern_schema_getpatternschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addpattern/": { - "post": { - "summary": "Fastapi Add Pattern", - "operationId": "fastapi_add_pattern_addpattern__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pattern", - "type": "string" - }, - "name": "pattern", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletepattern/": { - "post": { - "summary": "Fastapi Delete Pattern", - "operationId": "fastapi_delete_pattern_deletepattern__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pattern", - "type": "string" - }, - "name": "pattern", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpatternproperties/": { - "get": { - "summary": "Fastapi Get Pattern Properties", - "operationId": "fastapi_get_pattern_properties_getpatternproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pattern", - "type": "string" - }, - "name": "pattern", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpatternproperties/": { - "post": { - "summary": "Fastapi Set Pattern Properties", - "operationId": "fastapi_set_pattern_properties_setpatternproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pattern", - "type": "string" - }, - "name": "pattern", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getcurveschema": { - "get": { - "summary": "Fastapi Get Curve Schema", - "operationId": "fastapi_get_curve_schema_getcurveschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addcurve/": { - "post": { - "summary": "Fastapi Add Curve", - "operationId": "fastapi_add_curve_addcurve__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Curve", - "type": "string" - }, - "name": "curve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletecurve/": { - "post": { - "summary": "Fastapi Delete Curve", - "operationId": "fastapi_delete_curve_deletecurve__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Curve", - "type": "string" - }, - "name": "curve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getcurveproperties/": { - "get": { - "summary": "Fastapi Get Curve Properties", - "operationId": "fastapi_get_curve_properties_getcurveproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Curve", - "type": "string" - }, - "name": "curve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setcurveproperties/": { - "post": { - "summary": "Fastapi Set Curve Properties", - "operationId": "fastapi_set_curve_properties_setcurveproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Curve", - "type": "string" - }, - "name": "curve", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getcontrolschema/": { - "get": { - "summary": "Fastapi Get Control Schema", - "operationId": "fastapi_get_control_schema_getcontrolschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getcontrolproperties/": { - "get": { - "summary": "Fastapi Get Control Properties", - "operationId": "fastapi_get_control_properties_getcontrolproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setcontrolproperties/": { - "post": { - "summary": "Fastapi Set Control Properties", - "operationId": "fastapi_set_control_properties_setcontrolproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getruleschema/": { - "get": { - "summary": "Fastapi Get Rule Schema", - "operationId": "fastapi_get_rule_schema_getruleschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getruleproperties/": { - "get": { - "summary": "Fastapi Get Rule Properties", - "operationId": "fastapi_get_rule_properties_getruleproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setruleproperties/": { - "post": { - "summary": "Fastapi Set Rule Properties", - "operationId": "fastapi_set_rule_properties_setruleproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getenergyschema/": { - "get": { - "summary": "Fastapi Get Energy Schema", - "operationId": "fastapi_get_energy_schema_getenergyschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getenergyproperties/": { - "get": { - "summary": "Fastapi Get Energy Properties", - "operationId": "fastapi_get_energy_properties_getenergyproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setenergyproperties/": { - "post": { - "summary": "Fastapi Set Energy Properties", - "operationId": "fastapi_set_energy_properties_setenergyproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpumpenergyschema/": { - "get": { - "summary": "Fastapi Get Pump Energy Schema", - "operationId": "fastapi_get_pump_energy_schema_getpumpenergyschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpumpenergyproperties//": { - "get": { - "summary": "Fastapi Get Pump Energy Proeprties", - "operationId": "fastapi_get_pump_energy_proeprties_getpumpenergyproperties___get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpumpenergyproperties//": { - "get": { - "summary": "Fastapi Set Pump Energy Properties", - "operationId": "fastapi_set_pump_energy_properties_setpumpenergyproperties___get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pump", - "type": "string" - }, - "name": "pump", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getemitterschema": { - "get": { - "summary": "Fastapi Get Emitter Schema", - "operationId": "fastapi_get_emitter_schema_getemitterschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getemitterproperties/": { - "get": { - "summary": "Fastapi Get Emitter Properties", - "operationId": "fastapi_get_emitter_properties_getemitterproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setemitterproperties/": { - "post": { - "summary": "Fastapi Set Emitter Properties", - "operationId": "fastapi_set_emitter_properties_setemitterproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Junction", - "type": "string" - }, - "name": "junction", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getqualityschema/": { - "get": { - "summary": "Fastapi Get Quality Schema", - "operationId": "fastapi_get_quality_schema_getqualityschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getqualityproperties/": { - "get": { - "summary": "Fastapi Get Quality Properties", - "operationId": "fastapi_get_quality_properties_getqualityproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setqualityproperties/": { - "post": { - "summary": "Fastapi Set Quality Properties", - "operationId": "fastapi_set_quality_properties_setqualityproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getsourcechema/": { - "get": { - "summary": "Fastapi Get Source Schema", - "operationId": "fastapi_get_source_schema_getsourcechema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getsource/": { - "get": { - "summary": "Fastapi Get Source", - "operationId": "fastapi_get_source_getsource__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setsource/": { - "post": { - "summary": "Fastapi Set Source", - "operationId": "fastapi_set_source_setsource__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addsource/": { - "post": { - "summary": "Fastapi Add Source", - "operationId": "fastapi_add_source_addsource__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletesource/": { - "post": { - "summary": "Fastapi Delete Source", - "operationId": "fastapi_delete_source_deletesource__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreactionschema/": { - "get": { - "summary": "Fastapi Get Reaction Schema", - "operationId": "fastapi_get_reaction_schema_getreactionschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getreaction/": { - "get": { - "summary": "Fastapi Get Reaction", - "operationId": "fastapi_get_reaction_getreaction__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setreaction/": { - "post": { - "summary": "Fastapi Set Reaction", - "operationId": "fastapi_set_reaction_setreaction__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipereactionschema/": { - "get": { - "summary": "Fastapi Get Pipe Reaction Schema", - "operationId": "fastapi_get_pipe_reaction_schema_getpipereactionschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getpipereaction/": { - "get": { - "summary": "Fastapi Get Pipe Reaction", - "operationId": "fastapi_get_pipe_reaction_getpipereaction__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Pipe", - "type": "string" - }, - "name": "pipe", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setpipereaction/": { - "post": { - "summary": "Fastapi Set Pipe Reaction", - "operationId": "fastapi_set_pipe_reaction_setpipereaction__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankreactionschema/": { - "get": { - "summary": "Fastapi Get Tank Reaction Schema", - "operationId": "fastapi_get_tank_reaction_schema_gettankreactionschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettankreaction/": { - "get": { - "summary": "Fastapi Get Tank Reaction", - "operationId": "fastapi_get_tank_reaction_gettankreaction__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settankreaction/": { - "post": { - "summary": "Fastapi Set Tank Reaction", - "operationId": "fastapi_set_tank_reaction_settankreaction__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getmixingschema/": { - "get": { - "summary": "Fastapi Get Mixing Schema", - "operationId": "fastapi_get_mixing_schema_getmixingschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getmixing/": { - "get": { - "summary": "Fastapi Get Mixing", - "operationId": "fastapi_get_mixing_getmixing__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Tank", - "type": "string" - }, - "name": "tank", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setmixing/": { - "post": { - "summary": "Fastapi Set Mixing", - "operationId": "fastapi_set_mixing_setmixing__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addmixing/": { - "post": { - "summary": "Fastapi Add Mixing", - "operationId": "fastapi_add_mixing_addmixing__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletemixing/": { - "post": { - "summary": "Fastapi Delete Mixing", - "operationId": "fastapi_delete_mixing_deletemixing__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettimeschema": { - "get": { - "summary": "Fastapi Get Time Schema", - "operationId": "fastapi_get_time_schema_gettimeschema_get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/gettimeproperties/": { - "get": { - "summary": "Fastapi Get Time Properties", - "operationId": "fastapi_get_time_properties_gettimeproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/settimeproperties/": { - "post": { - "summary": "Fastapi Set Time Properties", - "operationId": "fastapi_set_time_properties_settimeproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getoptionschema/": { - "get": { - "summary": "Fastapi Get Option Schema", - "operationId": "fastapi_get_option_schema_getoptionschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getoptionproperties/": { - "get": { - "summary": "Fastapi Get Option Properties", - "operationId": "fastapi_get_option_properties_getoptionproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setoptionproperties/": { - "post": { - "summary": "Fastapi Set Option Properties", - "operationId": "fastapi_set_option_properties_setoptionproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getnodecoord/": { - "get": { - "summary": "Fastapi Get Node Coord", - "operationId": "fastapi_get_node_coord_getnodecoord__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Node", - "type": "string" - }, - "name": "node", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getnetworkcoords/": { - "get": { - "summary": "Fastapi Get Network Coords", - "operationId": "fastapi_get_network_coords_getnetworkcoords__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getmajornodecoords/": { - "get": { - "summary": "Fastapi Get Major Node Coords", - "operationId": "fastapi_get_major_node_coords_getmajornodecoords__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Diameter", - "type": "integer" - }, - "name": "diameter", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getnetworklinknodes/": { - "get": { - "summary": "Fastapi Get Network Link Nodes", - "operationId": "fastapi_get_network_link_nodes_getnetworklinknodes__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getmajorpipenodes/": { - "get": { - "summary": "Fastapi Get Major Pipe Nodes", - "operationId": "fastapi_get_major_pipe_nodes_getmajorpipenodes__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Diameter", - "type": "integer" - }, - "name": "diameter", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvertexschema/": { - "get": { - "summary": "Fastapi Get Vertex Schema", - "operationId": "fastapi_get_vertex_schema_getvertexschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvertexproperties/": { - "get": { - "summary": "Fastapi Get Vertex Properties", - "operationId": "fastapi_get_vertex_properties_getvertexproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Link", - "type": "string" - }, - "name": "link", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvertexproperties/": { - "post": { - "summary": "Fastapi Set Vertex Properties", - "operationId": "fastapi_set_vertex_properties_setvertexproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addvertex/": { - "post": { - "summary": "Fastapi Add Vertex", - "operationId": "fastapi_add_vertex_addvertex__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletevertex/": { - "post": { - "summary": "Fastapi Delete Vertex", - "operationId": "fastapi_delete_vertex_deletevertex__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getallvertexlinks/": { - "get": { - "summary": "Fastapi Get All Vertex Links", - "operationId": "fastapi_get_all_vertex_links_getallvertexlinks__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getallvertices/": { - "get": { - "summary": "Fastapi Get All Vertices", - "operationId": "fastapi_get_all_vertices_getallvertices__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getlabelschema/": { - "get": { - "summary": "Fastapi Get Label Schema", - "operationId": "fastapi_get_label_schema_getlabelschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getlabelproperties/": { - "get": { - "summary": "Fastapi Get Label Properties", - "operationId": "fastapi_get_label_properties_getlabelproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "X", - "type": "number" - }, - "name": "x", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Y", - "type": "number" - }, - "name": "y", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setlabelproperties/": { - "post": { - "summary": "Fastapi Set Label Properties", - "operationId": "fastapi_set_label_properties_setlabelproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addlabel/": { - "post": { - "summary": "Fastapi Add Label", - "operationId": "fastapi_add_label_addlabel__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletelabel/": { - "post": { - "summary": "Fastapi Delete Label", - "operationId": "fastapi_delete_label_deletelabel__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getbackdropschema/": { - "get": { - "summary": "Fastapi Get Backdrop Schema", - "operationId": "fastapi_get_backdrop_schema_getbackdropschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getbackdropproperties/": { - "get": { - "summary": "Fastapi Get Backdrop Properties", - "operationId": "fastapi_get_backdrop_properties_getbackdropproperties__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setbackdropproperties/": { - "post": { - "summary": "Fastapi Set Backdrop Properties", - "operationId": "fastapi_set_backdrop_properties_setbackdropproperties__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getscadadeviceschema/": { - "get": { - "summary": "Fastapi Get Scada Device Schema", - "operationId": "fastapi_get_scada_device_schema_getscadadeviceschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getscadadevice/": { - "get": { - "summary": "Fastapi Get Scada Device", - "operationId": "fastapi_get_scada_device_getscadadevice__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setscadadevice/": { - "post": { - "summary": "Fastapi Set Scada Device", - "operationId": "fastapi_set_scada_device_setscadadevice__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addscadadevice/": { - "post": { - "summary": "Fastapi Add Scada Device", - "operationId": "fastapi_add_scada_device_addscadadevice__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletescadadevice/": { - "post": { - "summary": "Fastapi Delete Scada Device", - "operationId": "fastapi_delete_scada_device_deletescadadevice__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/cleanscadadevice/": { - "post": { - "summary": "Fastapi Clean Scada Device", - "operationId": "fastapi_clean_scada_device_cleanscadadevice__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getallscadadeviceids/": { - "get": { - "summary": "Fastapi Get All Scada Device Ids", - "operationId": "fastapi_get_all_scada_device_ids_getallscadadeviceids__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getallscadadevices/": { - "get": { - "summary": "Fastapi Get All Scada Devices", - "operationId": "fastapi_get_all_scada_devices_getallscadadevices__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getscadadevicedataschema/": { - "get": { - "summary": "Fastapi Get Scada Device Data Schema", - "operationId": "fastapi_get_scada_device_data_schema_getscadadevicedataschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getscadadevicedata/": { - "get": { - "summary": "Fastapi Get Scada Device Data", - "operationId": "fastapi_get_scada_device_data_getscadadevicedata__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setscadadevicedata/": { - "post": { - "summary": "Fastapi Set Scada Device Data", - "operationId": "fastapi_set_scada_device_data_setscadadevicedata__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addscadadevicedata/": { - "post": { - "summary": "Fastapi Add Scada Device Data", - "operationId": "fastapi_add_scada_device_data_addscadadevicedata__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletescadadevicedata/": { - "post": { - "summary": "Fastapi Delete Scada Device Data", - "operationId": "fastapi_delete_scada_device_data_deletescadadevicedata__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/cleanscadadevicedata/": { - "post": { - "summary": "Fastapi Clean Scada Device Data", - "operationId": "fastapi_clean_scada_device_data_cleanscadadevicedata__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getscadaelementschema/": { - "get": { - "summary": "Fastapi Get Scada Element Schema", - "operationId": "fastapi_get_scada_element_schema_getscadaelementschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getscadaelements/": { - "get": { - "summary": "Fastapi Get Scada Elements", - "operationId": "fastapi_get_scada_elements_getscadaelements__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getscadaelement/": { - "get": { - "summary": "Fastapi Get Scada Element", - "operationId": "fastapi_get_scada_element_getscadaelement__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setscadaelement/": { - "post": { - "summary": "Fastapi Set Scada Element", - "operationId": "fastapi_set_scada_element_setscadaelement__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addscadaelement/": { - "post": { - "summary": "Fastapi Add Scada Element", - "operationId": "fastapi_add_scada_element_addscadaelement__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletescadaelement/": { - "post": { - "summary": "Fastapi Delete Scada Element", - "operationId": "fastapi_delete_scada_element_deletescadaelement__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/cleanscadaelement/": { - "post": { - "summary": "Fastapi Clean Scada Element", - "operationId": "fastapi_clean_scada_element_cleanscadaelement__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getregionschema/": { - "get": { - "summary": "Fastapi Get Region Schema", - "operationId": "fastapi_get_region_schema_getregionschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getregion/": { - "get": { - "summary": "Fastapi Get Region", - "operationId": "fastapi_get_region_getregion__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setregion/": { - "post": { - "summary": "Fastapi Set Region", - "operationId": "fastapi_set_region_setregion__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addregion/": { - "post": { - "summary": "Fastapi Add Region", - "operationId": "fastapi_add_region_addregion__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deleteregion/": { - "post": { - "summary": "Fastapi Delete Region", - "operationId": "fastapi_delete_region_deleteregion__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculatedistrictmeteringareafornodes/": { - "get": { - "summary": "Fastapi Calculate District Metering Area For Nodes", - "operationId": "fastapi_calculate_district_metering_area_for_nodes_calculatedistrictmeteringareafornodes__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculatedistrictmeteringareaforregion/": { - "get": { - "summary": "Fastapi Calculate District Metering Area For Region", - "operationId": "fastapi_calculate_district_metering_area_for_region_calculatedistrictmeteringareaforregion__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculatedistrictmeteringareafornetwork/": { - "get": { - "summary": "Fastapi Calculate District Metering Area For Network", - "operationId": "fastapi_calculate_district_metering_area_for_network_calculatedistrictmeteringareafornetwork__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getdistrictmeteringareaschema/": { - "get": { - "summary": "Fastapi Get District Metering Area Schema", - "operationId": "fastapi_get_district_metering_area_schema_getdistrictmeteringareaschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getdistrictmeteringarea/": { - "get": { - "summary": "Fastapi Get District Metering Area", - "operationId": "fastapi_get_district_metering_area_getdistrictmeteringarea__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setdistrictmeteringarea/": { - "post": { - "summary": "Fastapi Set District Metering Area", - "operationId": "fastapi_set_district_metering_area_setdistrictmeteringarea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/adddistrictmeteringarea/": { - "post": { - "summary": "Fastapi Add District Metering Area", - "operationId": "fastapi_add_district_metering_area_adddistrictmeteringarea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletedistrictmeteringarea/": { - "post": { - "summary": "Fastapi Delete District Metering Area", - "operationId": "fastapi_delete_district_metering_area_deletedistrictmeteringarea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getalldistrictmeteringareaids/": { - "get": { - "summary": "Fastapi Get All District Metering Area Ids", - "operationId": "fastapi_get_all_district_metering_area_ids_getalldistrictmeteringareaids__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getalldistrictmeteringareas/": { - "get": { - "summary": "Getalldistrictmeteringareas", - "operationId": "getalldistrictmeteringareas_getalldistrictmeteringareas__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/generatedistrictmeteringarea/": { - "post": { - "summary": "Fastapi Generate District Metering Area", - "operationId": "fastapi_generate_district_metering_area_generatedistrictmeteringarea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Part Count", - "type": "integer" - }, - "name": "part_count", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Part Type", - "type": "integer" - }, - "name": "part_type", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Inflate Delta", - "type": "number" - }, - "name": "inflate_delta", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/generatesubdistrictmeteringarea/": { - "post": { - "summary": "Fastapi Generate Sub District Metering Area", - "operationId": "fastapi_generate_sub_district_metering_area_generatesubdistrictmeteringarea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Dma", - "type": "string" - }, - "name": "dma", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Part Count", - "type": "integer" - }, - "name": "part_count", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Part Type", - "type": "integer" - }, - "name": "part_type", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Inflate Delta", - "type": "number" - }, - "name": "inflate_delta", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculateservicearea/": { - "get": { - "summary": "Fastapi Calculate Service Area", - "operationId": "fastapi_calculate_service_area_calculateservicearea__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Time Index", - "type": "integer" - }, - "name": "time_index", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getserviceareaschema/": { - "get": { - "summary": "Fastapi Get Service Area Schema", - "operationId": "fastapi_get_service_area_schema_getserviceareaschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getservicearea/": { - "get": { - "summary": "Fastapi Get Service Area", - "operationId": "fastapi_get_service_area_getservicearea__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setservicearea/": { - "post": { - "summary": "Fastapi Set Service Area", - "operationId": "fastapi_set_service_area_setservicearea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addservicearea/": { - "post": { - "summary": "Fastapi Add Service Area", - "operationId": "fastapi_add_service_area_addservicearea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deleteservicearea/": { - "post": { - "summary": "Fastapi Delete Service Area", - "operationId": "fastapi_delete_service_area_deleteservicearea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getallserviceareas/": { - "get": { - "summary": "Fastapi Get All Service Areas", - "operationId": "fastapi_get_all_service_areas_getallserviceareas__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/generateservicearea/": { - "post": { - "summary": "Fastapi Generate Service Area", - "operationId": "fastapi_generate_service_area_generateservicearea__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Inflate Delta", - "type": "number" - }, - "name": "inflate_delta", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculatevirtualdistrict/": { - "get": { - "summary": "Fastapi Calculate Virtual District", - "operationId": "fastapi_calculate_virtual_district_calculatevirtualdistrict__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "title": "Centers", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvirtualdistrictschema/": { - "get": { - "summary": "Fastapi Get Virtual District Schema", - "operationId": "fastapi_get_virtual_district_schema_getvirtualdistrictschema__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getvirtualdistrict/": { - "get": { - "summary": "Fastapi Get Virtual District", - "operationId": "fastapi_get_virtual_district_getvirtualdistrict__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Id", - "type": "string" - }, - "name": "id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/setvirtualdistrict/": { - "post": { - "summary": "Fastapi Set Virtual District", - "operationId": "fastapi_set_virtual_district_setvirtualdistrict__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/addvirtualdistrict/": { - "post": { - "summary": "Fastapi Add Virtual District", - "operationId": "fastapi_add_virtual_district_addvirtualdistrict__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/deletevirtualdistrict/": { - "post": { - "summary": "Fastapi Delete Virtual District", - "operationId": "fastapi_delete_virtual_district_deletevirtualdistrict__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/getallvirtualdistrict/": { - "get": { - "summary": "Fastapi Get All Virtual District", - "operationId": "fastapi_get_all_virtual_district_getallvirtualdistrict__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/generatevirtualdistrict/": { - "post": { - "summary": "Fastapi Generate Virtual District", - "operationId": "fastapi_generate_virtual_district_generatevirtualdistrict__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Inflate Delta", - "type": "number" - }, - "name": "inflate_delta", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculatedemandtonodes/": { - "get": { - "summary": "Fastapi Calculate Demand To Nodes", - "operationId": "fastapi_calculate_demand_to_nodes_calculatedemandtonodes__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculatedemandtoregion/": { - "get": { - "summary": "Fastapi Calculate Demand To Region", - "operationId": "fastapi_calculate_demand_to_region_calculatedemandtoregion__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/calculatedemandtonetwork/": { - "get": { - "summary": "Fastapi Calculate Demand To Network", - "operationId": "fastapi_calculate_demand_to_network_calculatedemandtonetwork__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Network", - "type": "string" - }, - "name": "network", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Demand", - "type": "number" - }, - "name": "demand", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/uploadinp/": { - "post": { - "summary": "Upload Inp", - "operationId": "upload_inp_uploadinp__post", - "parameters": [ - { - "required": true, - "schema": { - "title": "Afile", - "type": "string", - "format": "binary" - }, - "name": "afile", - "in": "query" - }, - { - "required": true, - "schema": { - "title": "Name", - "type": "string" - }, - "name": "name", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/downloadinp/": { - "get": { - "summary": "Download Inp", - "operationId": "download_inp_downloadinp__get", - "parameters": [ - { - "required": true, - "schema": { - "title": "Name", - "type": "string" - }, - "name": "name", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } - } - } - } - }, - "/convertv3tov2/": { - "get": { - "summary": "Fastapi Convert V3 To V2", - "operationId": "fastapi_convert_v3_to_v2_convertv3tov2__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - } - } - } - }, - "/getjson/": { - "get": { - "summary": "Get Json", - "operationId": "get_json_getjson__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - } - } - } - }, - "/getrealtimedata/": { - "get": { - "summary": "Get Realtimedata", - "operationId": "get_realtimedata_getrealtimedata__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - } - } - } - }, - "/getsimulationresult/": { - "get": { - "summary": "Get Simulationresult", - "operationId": "get_simulationresult_getsimulationresult__get", - "responses": { - "200": { - "description": "Successful Response", - "content": { - "application/json": { - "schema": {} - } - } - } - } - } - } - }, - "components": { - "schemas": { - "HTTPValidationError": { - "title": "HTTPValidationError", - "type": "object", - "properties": { - "detail": { - "title": "Detail", - "type": "array", - "items": { - "$ref": "#/components/schemas/ValidationError" - } - } - } - }, - "ValidationError": { - "title": "ValidationError", - "required": [ - "loc", - "msg", - "type" - ], - "type": "object", - "properties": { - "loc": { - "title": "Location", - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "integer" - } - ] - } - }, - "msg": { - "title": "Message", - "type": "string" - }, - "type": { - "title": "Error Type", - "type": "string" - } - } - } - } - } -} \ No newline at end of file diff --git a/project_info.py b/project_info.py deleted file mode 100644 index a5555d1..0000000 --- a/project_info.py +++ /dev/null @@ -1 +0,0 @@ -name='szh' \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 8f20578..259c4e2 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/20250309beibei_v2.inp b/resources/20250309beibei_v2.inp similarity index 100% rename from 20250309beibei_v2.inp rename to resources/20250309beibei_v2.inp diff --git a/fx0217-mass injection.inp b/resources/fx0217-mass injection.inp similarity index 100% rename from fx0217-mass injection.inp rename to resources/fx0217-mass injection.inp diff --git a/history_pattern_flow.csv b/resources/history_pattern_flow.csv similarity index 100% rename from history_pattern_flow.csv rename to resources/history_pattern_flow.csv diff --git a/model22_1223.inp b/resources/model22_1223.inp similarity index 100% rename from model22_1223.inp rename to resources/model22_1223.inp diff --git a/resources/old_requirements.txt b/resources/old_requirements.txt new file mode 100644 index 0000000..5b04d85 Binary files /dev/null and b/resources/old_requirements.txt differ diff --git a/scada_info.csv b/resources/scada_info.csv similarity index 100% rename from scada_info.csv rename to resources/scada_info.csv diff --git a/resources/sql/001_create_users_table.sql b/resources/sql/001_create_users_table.sql new file mode 100644 index 0000000..d0eb301 --- /dev/null +++ b/resources/sql/001_create_users_table.sql @@ -0,0 +1,67 @@ +-- ============================================ +-- TJWater Server 用户系统数据库迁移脚本 +-- ============================================ + +-- 创建用户表 +CREATE TABLE IF NOT EXISTS users ( + id SERIAL PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + email VARCHAR(100) UNIQUE NOT NULL, + hashed_password VARCHAR(255) NOT NULL, + role VARCHAR(20) DEFAULT 'USER' NOT NULL, + is_active BOOLEAN DEFAULT TRUE NOT NULL, + is_superuser BOOLEAN DEFAULT FALSE NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + + CONSTRAINT users_role_check CHECK (role IN ('ADMIN', 'OPERATOR', 'USER', 'VIEWER')) +); + +-- 创建索引 +CREATE INDEX IF NOT EXISTS idx_users_username ON users(username); +CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); +CREATE INDEX IF NOT EXISTS idx_users_role ON users(role); +CREATE INDEX IF NOT EXISTS idx_users_is_active ON users(is_active); + +-- 创建触发器自动更新 updated_at +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +DROP TRIGGER IF EXISTS update_users_updated_at ON users; +CREATE TRIGGER update_users_updated_at + BEFORE UPDATE ON users + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); + +-- 创建默认管理员账号 (密码: admin123) +INSERT INTO users (username, email, hashed_password, role, is_superuser) +VALUES ( + 'admin', + 'admin@tjwater.com', + '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5aeAJK.1tYKAW', + 'ADMIN', + TRUE +) ON CONFLICT (username) DO NOTHING; + +-- 迁移现有硬编码用户 (tjwater/tjwater@123) +INSERT INTO users (username, email, hashed_password, role, is_superuser) +VALUES ( + 'tjwater', + 'tjwater@tjwater.com', + '$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW', + 'ADMIN', + TRUE +) ON CONFLICT (username) DO NOTHING; + +-- 添加注释 +COMMENT ON TABLE users IS '用户表 - 存储系统用户信息'; +COMMENT ON COLUMN users.id IS '用户ID(主键)'; +COMMENT ON COLUMN users.username IS '用户名(唯一)'; +COMMENT ON COLUMN users.email IS '邮箱地址(唯一)'; +COMMENT ON COLUMN users.hashed_password IS 'bcrypt 密码哈希'; +COMMENT ON COLUMN users.role IS '用户角色: ADMIN, OPERATOR, USER, VIEWER'; diff --git a/resources/sql/002_create_audit_logs_table.sql b/resources/sql/002_create_audit_logs_table.sql new file mode 100644 index 0000000..5fdc1c1 --- /dev/null +++ b/resources/sql/002_create_audit_logs_table.sql @@ -0,0 +1,45 @@ +-- ============================================ +-- TJWater Server 审计日志表迁移脚本 +-- ============================================ + +-- 创建审计日志表 +CREATE TABLE IF NOT EXISTS audit_logs ( + id SERIAL PRIMARY KEY, + user_id INTEGER REFERENCES users(id) ON DELETE SET NULL, + username VARCHAR(50), + action VARCHAR(50) NOT NULL, + resource_type VARCHAR(50), + resource_id VARCHAR(100), + ip_address VARCHAR(45), + user_agent TEXT, + request_method VARCHAR(10), + request_path TEXT, + request_data JSONB, + response_status INTEGER, + error_message TEXT, + timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +-- 创建索引以提高查询性能 +CREATE INDEX IF NOT EXISTS idx_audit_logs_user_id ON audit_logs(user_id); +CREATE INDEX IF NOT EXISTS idx_audit_logs_username ON audit_logs(username); +CREATE INDEX IF NOT EXISTS idx_audit_logs_timestamp ON audit_logs(timestamp DESC); +CREATE INDEX IF NOT EXISTS idx_audit_logs_action ON audit_logs(action); +CREATE INDEX IF NOT EXISTS idx_audit_logs_resource ON audit_logs(resource_type, resource_id); + +-- 添加注释 +COMMENT ON TABLE audit_logs IS '审计日志表 - 记录所有关键操作'; +COMMENT ON COLUMN audit_logs.id IS '日志ID(主键)'; +COMMENT ON COLUMN audit_logs.user_id IS '用户ID(外键)'; +COMMENT ON COLUMN audit_logs.username IS '用户名(冗余字段,用于用户删除后仍可查询)'; +COMMENT ON COLUMN audit_logs.action IS '操作类型(如:LOGIN, LOGOUT, CREATE, UPDATE, DELETE)'; +COMMENT ON COLUMN audit_logs.resource_type IS '资源类型(如:user, project, network)'; +COMMENT ON COLUMN audit_logs.resource_id IS '资源ID'; +COMMENT ON COLUMN audit_logs.ip_address IS '客户端IP地址'; +COMMENT ON COLUMN audit_logs.user_agent IS '客户端User-Agent'; +COMMENT ON COLUMN audit_logs.request_method IS 'HTTP请求方法'; +COMMENT ON COLUMN audit_logs.request_path IS '请求路径'; +COMMENT ON COLUMN audit_logs.request_data IS '请求数据(JSON格式,敏感信息已脱敏)'; +COMMENT ON COLUMN audit_logs.response_status IS 'HTTP响应状态码'; +COMMENT ON COLUMN audit_logs.error_message IS '错误消息(如果有)'; +COMMENT ON COLUMN audit_logs.timestamp IS '操作时间'; diff --git a/script/sql/create/0.base.sql b/resources/sql/create/0.base.sql similarity index 100% rename from script/sql/create/0.base.sql rename to resources/sql/create/0.base.sql diff --git a/script/sql/create/1.title.sql b/resources/sql/create/1.title.sql similarity index 100% rename from script/sql/create/1.title.sql rename to resources/sql/create/1.title.sql diff --git a/script/sql/create/10.status.sql b/resources/sql/create/10.status.sql similarity index 100% rename from script/sql/create/10.status.sql rename to resources/sql/create/10.status.sql diff --git a/script/sql/create/11.patterns.sql b/resources/sql/create/11.patterns.sql similarity index 100% rename from script/sql/create/11.patterns.sql rename to resources/sql/create/11.patterns.sql diff --git a/script/sql/create/12.curves.sql b/resources/sql/create/12.curves.sql similarity index 100% rename from script/sql/create/12.curves.sql rename to resources/sql/create/12.curves.sql diff --git a/script/sql/create/13.controls.sql b/resources/sql/create/13.controls.sql similarity index 100% rename from script/sql/create/13.controls.sql rename to resources/sql/create/13.controls.sql diff --git a/script/sql/create/14.rules.sql b/resources/sql/create/14.rules.sql similarity index 100% rename from script/sql/create/14.rules.sql rename to resources/sql/create/14.rules.sql diff --git a/script/sql/create/15.energy.sql b/resources/sql/create/15.energy.sql similarity index 100% rename from script/sql/create/15.energy.sql rename to resources/sql/create/15.energy.sql diff --git a/script/sql/create/16.emitters.sql b/resources/sql/create/16.emitters.sql similarity index 100% rename from script/sql/create/16.emitters.sql rename to resources/sql/create/16.emitters.sql diff --git a/script/sql/create/17.quality.sql b/resources/sql/create/17.quality.sql similarity index 100% rename from script/sql/create/17.quality.sql rename to resources/sql/create/17.quality.sql diff --git a/script/sql/create/18.sources.sql b/resources/sql/create/18.sources.sql similarity index 100% rename from script/sql/create/18.sources.sql rename to resources/sql/create/18.sources.sql diff --git a/script/sql/create/19.reactions.sql b/resources/sql/create/19.reactions.sql similarity index 100% rename from script/sql/create/19.reactions.sql rename to resources/sql/create/19.reactions.sql diff --git a/script/sql/create/2.junctions.sql b/resources/sql/create/2.junctions.sql similarity index 100% rename from script/sql/create/2.junctions.sql rename to resources/sql/create/2.junctions.sql diff --git a/script/sql/create/20.mixing.sql b/resources/sql/create/20.mixing.sql similarity index 100% rename from script/sql/create/20.mixing.sql rename to resources/sql/create/20.mixing.sql diff --git a/script/sql/create/21.times.sql b/resources/sql/create/21.times.sql similarity index 100% rename from script/sql/create/21.times.sql rename to resources/sql/create/21.times.sql diff --git a/script/sql/create/22.report.sql b/resources/sql/create/22.report.sql similarity index 100% rename from script/sql/create/22.report.sql rename to resources/sql/create/22.report.sql diff --git a/script/sql/create/23.options.sql b/resources/sql/create/23.options.sql similarity index 100% rename from script/sql/create/23.options.sql rename to resources/sql/create/23.options.sql diff --git a/script/sql/create/24.coordinates.sql b/resources/sql/create/24.coordinates.sql similarity index 100% rename from script/sql/create/24.coordinates.sql rename to resources/sql/create/24.coordinates.sql diff --git a/script/sql/create/25.vertices.sql b/resources/sql/create/25.vertices.sql similarity index 100% rename from script/sql/create/25.vertices.sql rename to resources/sql/create/25.vertices.sql diff --git a/script/sql/create/26.labels.sql b/resources/sql/create/26.labels.sql similarity index 100% rename from script/sql/create/26.labels.sql rename to resources/sql/create/26.labels.sql diff --git a/script/sql/create/27.backdrop.sql b/resources/sql/create/27.backdrop.sql similarity index 100% rename from script/sql/create/27.backdrop.sql rename to resources/sql/create/27.backdrop.sql diff --git a/script/sql/create/28.end.sql b/resources/sql/create/28.end.sql similarity index 100% rename from script/sql/create/28.end.sql rename to resources/sql/create/28.end.sql diff --git a/script/sql/create/29.scada_device.sql b/resources/sql/create/29.scada_device.sql similarity index 100% rename from script/sql/create/29.scada_device.sql rename to resources/sql/create/29.scada_device.sql diff --git a/script/sql/create/3.reservoirs.sql b/resources/sql/create/3.reservoirs.sql similarity index 100% rename from script/sql/create/3.reservoirs.sql rename to resources/sql/create/3.reservoirs.sql diff --git a/script/sql/create/30.scada_device_data.sql b/resources/sql/create/30.scada_device_data.sql similarity index 100% rename from script/sql/create/30.scada_device_data.sql rename to resources/sql/create/30.scada_device_data.sql diff --git a/script/sql/create/31.scada_element.sql b/resources/sql/create/31.scada_element.sql similarity index 100% rename from script/sql/create/31.scada_element.sql rename to resources/sql/create/31.scada_element.sql diff --git a/script/sql/create/32.region.sql b/resources/sql/create/32.region.sql similarity index 100% rename from script/sql/create/32.region.sql rename to resources/sql/create/32.region.sql diff --git a/script/sql/create/33.dma.sql b/resources/sql/create/33.dma.sql similarity index 100% rename from script/sql/create/33.dma.sql rename to resources/sql/create/33.dma.sql diff --git a/script/sql/create/34.sa.sql b/resources/sql/create/34.sa.sql similarity index 100% rename from script/sql/create/34.sa.sql rename to resources/sql/create/34.sa.sql diff --git a/script/sql/create/35.vd.sql b/resources/sql/create/35.vd.sql similarity index 100% rename from script/sql/create/35.vd.sql rename to resources/sql/create/35.vd.sql diff --git a/script/sql/create/36.wda.sql b/resources/sql/create/36.wda.sql similarity index 100% rename from script/sql/create/36.wda.sql rename to resources/sql/create/36.wda.sql diff --git a/script/sql/create/37.history_patterns_flows.sql b/resources/sql/create/37.history_patterns_flows.sql similarity index 100% rename from script/sql/create/37.history_patterns_flows.sql rename to resources/sql/create/37.history_patterns_flows.sql diff --git a/script/sql/create/38.scada_info.sql b/resources/sql/create/38.scada_info.sql similarity index 100% rename from script/sql/create/38.scada_info.sql rename to resources/sql/create/38.scada_info.sql diff --git a/script/sql/create/39.users.sql b/resources/sql/create/39.users.sql similarity index 100% rename from script/sql/create/39.users.sql rename to resources/sql/create/39.users.sql diff --git a/script/sql/create/4.tanks.sql b/resources/sql/create/4.tanks.sql similarity index 100% rename from script/sql/create/4.tanks.sql rename to resources/sql/create/4.tanks.sql diff --git a/script/sql/create/40.scheme_list.sql b/resources/sql/create/40.scheme_list.sql similarity index 100% rename from script/sql/create/40.scheme_list.sql rename to resources/sql/create/40.scheme_list.sql diff --git a/script/sql/create/41.pipe_risk_probability.sql b/resources/sql/create/41.pipe_risk_probability.sql similarity index 100% rename from script/sql/create/41.pipe_risk_probability.sql rename to resources/sql/create/41.pipe_risk_probability.sql diff --git a/script/sql/create/42.sensor_placement.sql b/resources/sql/create/42.sensor_placement.sql similarity index 100% rename from script/sql/create/42.sensor_placement.sql rename to resources/sql/create/42.sensor_placement.sql diff --git a/script/sql/create/43.burst_locate_result.sql b/resources/sql/create/43.burst_locate_result.sql similarity index 100% rename from script/sql/create/43.burst_locate_result.sql rename to resources/sql/create/43.burst_locate_result.sql diff --git a/script/sql/create/5.pipes.sql b/resources/sql/create/5.pipes.sql similarity index 100% rename from script/sql/create/5.pipes.sql rename to resources/sql/create/5.pipes.sql diff --git a/script/sql/create/6.pumps.sql b/resources/sql/create/6.pumps.sql similarity index 100% rename from script/sql/create/6.pumps.sql rename to resources/sql/create/6.pumps.sql diff --git a/script/sql/create/7.valves.sql b/resources/sql/create/7.valves.sql similarity index 100% rename from script/sql/create/7.valves.sql rename to resources/sql/create/7.valves.sql diff --git a/script/sql/create/8.tags.sql b/resources/sql/create/8.tags.sql similarity index 100% rename from script/sql/create/8.tags.sql rename to resources/sql/create/8.tags.sql diff --git a/script/sql/create/9.demands.sql b/resources/sql/create/9.demands.sql similarity index 100% rename from script/sql/create/9.demands.sql rename to resources/sql/create/9.demands.sql diff --git a/script/sql/create/extension_data.sql b/resources/sql/create/extension_data.sql similarity index 100% rename from script/sql/create/extension_data.sql rename to resources/sql/create/extension_data.sql diff --git a/script/sql/create/operation.sql b/resources/sql/create/operation.sql similarity index 100% rename from script/sql/create/operation.sql rename to resources/sql/create/operation.sql diff --git a/script/sql/drop/0.base.sql b/resources/sql/drop/0.base.sql similarity index 100% rename from script/sql/drop/0.base.sql rename to resources/sql/drop/0.base.sql diff --git a/script/sql/drop/1.title.sql b/resources/sql/drop/1.title.sql similarity index 100% rename from script/sql/drop/1.title.sql rename to resources/sql/drop/1.title.sql diff --git a/script/sql/drop/10.status.sql b/resources/sql/drop/10.status.sql similarity index 100% rename from script/sql/drop/10.status.sql rename to resources/sql/drop/10.status.sql diff --git a/script/sql/drop/11.patterns.sql b/resources/sql/drop/11.patterns.sql similarity index 100% rename from script/sql/drop/11.patterns.sql rename to resources/sql/drop/11.patterns.sql diff --git a/script/sql/drop/12.curves.sql b/resources/sql/drop/12.curves.sql similarity index 100% rename from script/sql/drop/12.curves.sql rename to resources/sql/drop/12.curves.sql diff --git a/script/sql/drop/13.controls.sql b/resources/sql/drop/13.controls.sql similarity index 100% rename from script/sql/drop/13.controls.sql rename to resources/sql/drop/13.controls.sql diff --git a/script/sql/drop/14.rules.sql b/resources/sql/drop/14.rules.sql similarity index 100% rename from script/sql/drop/14.rules.sql rename to resources/sql/drop/14.rules.sql diff --git a/script/sql/drop/15.energy.sql b/resources/sql/drop/15.energy.sql similarity index 100% rename from script/sql/drop/15.energy.sql rename to resources/sql/drop/15.energy.sql diff --git a/script/sql/drop/16.emitters.sql b/resources/sql/drop/16.emitters.sql similarity index 100% rename from script/sql/drop/16.emitters.sql rename to resources/sql/drop/16.emitters.sql diff --git a/script/sql/drop/17.quality.sql b/resources/sql/drop/17.quality.sql similarity index 100% rename from script/sql/drop/17.quality.sql rename to resources/sql/drop/17.quality.sql diff --git a/script/sql/drop/18.sources.sql b/resources/sql/drop/18.sources.sql similarity index 100% rename from script/sql/drop/18.sources.sql rename to resources/sql/drop/18.sources.sql diff --git a/script/sql/drop/19.reactions.sql b/resources/sql/drop/19.reactions.sql similarity index 100% rename from script/sql/drop/19.reactions.sql rename to resources/sql/drop/19.reactions.sql diff --git a/script/sql/drop/2.junctions.sql b/resources/sql/drop/2.junctions.sql similarity index 100% rename from script/sql/drop/2.junctions.sql rename to resources/sql/drop/2.junctions.sql diff --git a/script/sql/drop/20.mixing.sql b/resources/sql/drop/20.mixing.sql similarity index 100% rename from script/sql/drop/20.mixing.sql rename to resources/sql/drop/20.mixing.sql diff --git a/script/sql/drop/21.times.sql b/resources/sql/drop/21.times.sql similarity index 100% rename from script/sql/drop/21.times.sql rename to resources/sql/drop/21.times.sql diff --git a/script/sql/drop/22.report.sql b/resources/sql/drop/22.report.sql similarity index 100% rename from script/sql/drop/22.report.sql rename to resources/sql/drop/22.report.sql diff --git a/script/sql/drop/23.options.sql b/resources/sql/drop/23.options.sql similarity index 100% rename from script/sql/drop/23.options.sql rename to resources/sql/drop/23.options.sql diff --git a/script/sql/drop/24.coordinates.sql b/resources/sql/drop/24.coordinates.sql similarity index 100% rename from script/sql/drop/24.coordinates.sql rename to resources/sql/drop/24.coordinates.sql diff --git a/script/sql/drop/25.vertices.sql b/resources/sql/drop/25.vertices.sql similarity index 100% rename from script/sql/drop/25.vertices.sql rename to resources/sql/drop/25.vertices.sql diff --git a/script/sql/drop/26.labels.sql b/resources/sql/drop/26.labels.sql similarity index 100% rename from script/sql/drop/26.labels.sql rename to resources/sql/drop/26.labels.sql diff --git a/script/sql/drop/27.backdrop.sql b/resources/sql/drop/27.backdrop.sql similarity index 100% rename from script/sql/drop/27.backdrop.sql rename to resources/sql/drop/27.backdrop.sql diff --git a/script/sql/drop/28.end.sql b/resources/sql/drop/28.end.sql similarity index 100% rename from script/sql/drop/28.end.sql rename to resources/sql/drop/28.end.sql diff --git a/script/sql/drop/29.scada_device.sql b/resources/sql/drop/29.scada_device.sql similarity index 100% rename from script/sql/drop/29.scada_device.sql rename to resources/sql/drop/29.scada_device.sql diff --git a/script/sql/drop/3.reservoirs.sql b/resources/sql/drop/3.reservoirs.sql similarity index 100% rename from script/sql/drop/3.reservoirs.sql rename to resources/sql/drop/3.reservoirs.sql diff --git a/script/sql/drop/30.scada_device_data.sql b/resources/sql/drop/30.scada_device_data.sql similarity index 100% rename from script/sql/drop/30.scada_device_data.sql rename to resources/sql/drop/30.scada_device_data.sql diff --git a/script/sql/drop/31.scada_element.sql b/resources/sql/drop/31.scada_element.sql similarity index 100% rename from script/sql/drop/31.scada_element.sql rename to resources/sql/drop/31.scada_element.sql diff --git a/script/sql/drop/32.region.sql b/resources/sql/drop/32.region.sql similarity index 100% rename from script/sql/drop/32.region.sql rename to resources/sql/drop/32.region.sql diff --git a/script/sql/drop/33.dma.sql b/resources/sql/drop/33.dma.sql similarity index 100% rename from script/sql/drop/33.dma.sql rename to resources/sql/drop/33.dma.sql diff --git a/script/sql/drop/34.sa.sql b/resources/sql/drop/34.sa.sql similarity index 100% rename from script/sql/drop/34.sa.sql rename to resources/sql/drop/34.sa.sql diff --git a/script/sql/drop/35.vd.sql b/resources/sql/drop/35.vd.sql similarity index 100% rename from script/sql/drop/35.vd.sql rename to resources/sql/drop/35.vd.sql diff --git a/script/sql/drop/36.wda.sql b/resources/sql/drop/36.wda.sql similarity index 100% rename from script/sql/drop/36.wda.sql rename to resources/sql/drop/36.wda.sql diff --git a/script/sql/drop/37.history_patterns_flows.sql b/resources/sql/drop/37.history_patterns_flows.sql similarity index 100% rename from script/sql/drop/37.history_patterns_flows.sql rename to resources/sql/drop/37.history_patterns_flows.sql diff --git a/script/sql/drop/38.scada_info.sql b/resources/sql/drop/38.scada_info.sql similarity index 100% rename from script/sql/drop/38.scada_info.sql rename to resources/sql/drop/38.scada_info.sql diff --git a/script/sql/drop/39.users.sql b/resources/sql/drop/39.users.sql similarity index 100% rename from script/sql/drop/39.users.sql rename to resources/sql/drop/39.users.sql diff --git a/script/sql/drop/4.tanks.sql b/resources/sql/drop/4.tanks.sql similarity index 100% rename from script/sql/drop/4.tanks.sql rename to resources/sql/drop/4.tanks.sql diff --git a/script/sql/drop/40.scheme_list.sql b/resources/sql/drop/40.scheme_list.sql similarity index 100% rename from script/sql/drop/40.scheme_list.sql rename to resources/sql/drop/40.scheme_list.sql diff --git a/script/sql/drop/41.pipe_risk_probability.sql b/resources/sql/drop/41.pipe_risk_probability.sql similarity index 100% rename from script/sql/drop/41.pipe_risk_probability.sql rename to resources/sql/drop/41.pipe_risk_probability.sql diff --git a/script/sql/drop/42.sensor_placement.sql b/resources/sql/drop/42.sensor_placement.sql similarity index 100% rename from script/sql/drop/42.sensor_placement.sql rename to resources/sql/drop/42.sensor_placement.sql diff --git a/script/sql/drop/43.burst_locate_result.sql b/resources/sql/drop/43.burst_locate_result.sql similarity index 100% rename from script/sql/drop/43.burst_locate_result.sql rename to resources/sql/drop/43.burst_locate_result.sql diff --git a/script/sql/drop/5.pipes.sql b/resources/sql/drop/5.pipes.sql similarity index 100% rename from script/sql/drop/5.pipes.sql rename to resources/sql/drop/5.pipes.sql diff --git a/script/sql/drop/6.pumps.sql b/resources/sql/drop/6.pumps.sql similarity index 100% rename from script/sql/drop/6.pumps.sql rename to resources/sql/drop/6.pumps.sql diff --git a/script/sql/drop/7.valves.sql b/resources/sql/drop/7.valves.sql similarity index 100% rename from script/sql/drop/7.valves.sql rename to resources/sql/drop/7.valves.sql diff --git a/script/sql/drop/8.tags.sql b/resources/sql/drop/8.tags.sql similarity index 100% rename from script/sql/drop/8.tags.sql rename to resources/sql/drop/8.tags.sql diff --git a/script/sql/drop/9.demands.sql b/resources/sql/drop/9.demands.sql similarity index 100% rename from script/sql/drop/9.demands.sql rename to resources/sql/drop/9.demands.sql diff --git a/script/sql/drop/extension_data.sql b/resources/sql/drop/extension_data.sql similarity index 100% rename from script/sql/drop/extension_data.sql rename to resources/sql/drop/extension_data.sql diff --git a/script/sql/drop/operation.sql b/resources/sql/drop/operation.sql similarity index 100% rename from script/sql/drop/operation.sql rename to resources/sql/drop/operation.sql diff --git a/temp.rpt b/resources/temp.rpt similarity index 100% rename from temp.rpt rename to resources/temp.rpt diff --git a/北碚市政管线风险评价结果.xlsx b/resources/北碚市政管线风险评价结果.xlsx similarity index 100% rename from 北碚市政管线风险评价结果.xlsx rename to resources/北碚市政管线风险评价结果.xlsx diff --git a/市政管线.dbf b/resources/市政管线.dbf similarity index 100% rename from 市政管线.dbf rename to resources/市政管线.dbf diff --git a/市政管线.prj b/resources/市政管线.prj similarity index 100% rename from 市政管线.prj rename to resources/市政管线.prj diff --git a/市政管线.shp b/resources/市政管线.shp similarity index 100% rename from 市政管线.shp rename to resources/市政管线.shp diff --git a/市政管线.shx b/resources/市政管线.shx similarity index 100% rename from 市政管线.shx rename to resources/市政管线.shx diff --git a/标准cleaned_demand_data.csv b/resources/标准cleaned_demand_data.csv similarity index 100% rename from 标准cleaned_demand_data.csv rename to resources/标准cleaned_demand_data.csv diff --git a/script/package/PyMetis-2018.1-cp34-cp34m-win_amd64.whl b/script/package/PyMetis-2018.1-cp34-cp34m-win_amd64.whl deleted file mode 100644 index eb0f989..0000000 Binary files a/script/package/PyMetis-2018.1-cp34-cp34m-win_amd64.whl and /dev/null differ diff --git a/script/package/PyMetis-2019.1.1-cp35-cp35m-win_amd64.whl b/script/package/PyMetis-2019.1.1-cp35-cp35m-win_amd64.whl deleted file mode 100644 index c9c7475..0000000 Binary files a/script/package/PyMetis-2019.1.1-cp35-cp35m-win_amd64.whl and /dev/null differ diff --git a/script/package/PyMetis-2019.1.1-cp36-cp36m-win_amd64.whl b/script/package/PyMetis-2019.1.1-cp36-cp36m-win_amd64.whl deleted file mode 100644 index 139a7a7..0000000 Binary files a/script/package/PyMetis-2019.1.1-cp36-cp36m-win_amd64.whl and /dev/null differ diff --git a/script/package/PyMetis-2020.1-cp310-cp310-win_amd64.whl b/script/package/PyMetis-2020.1-cp310-cp310-win_amd64.whl deleted file mode 100644 index b6f524c..0000000 Binary files a/script/package/PyMetis-2020.1-cp310-cp310-win_amd64.whl and /dev/null differ diff --git a/script/package/PyMetis-2020.1-cp37-cp37m-win_amd64.whl b/script/package/PyMetis-2020.1-cp37-cp37m-win_amd64.whl deleted file mode 100644 index 076c417..0000000 Binary files a/script/package/PyMetis-2020.1-cp37-cp37m-win_amd64.whl and /dev/null differ diff --git a/script/package/PyMetis-2020.1-cp38-cp38-win_amd64.whl b/script/package/PyMetis-2020.1-cp38-cp38-win_amd64.whl deleted file mode 100644 index 11b739e..0000000 Binary files a/script/package/PyMetis-2020.1-cp38-cp38-win_amd64.whl and /dev/null differ diff --git a/script/package/PyMetis-2020.1-cp39-cp39-win_amd64.whl b/script/package/PyMetis-2020.1-cp39-cp39-win_amd64.whl deleted file mode 100644 index e77bcee..0000000 Binary files a/script/package/PyMetis-2020.1-cp39-cp39-win_amd64.whl and /dev/null differ diff --git a/script/package/pkg-pymetis-2023.1.1-py312h95578b8_4.tar b/script/package/pkg-pymetis-2023.1.1-py312h95578b8_4.tar deleted file mode 100644 index 0dd6b78..0000000 Binary files a/script/package/pkg-pymetis-2023.1.1-py312h95578b8_4.tar and /dev/null differ diff --git a/AutoPullGitChanges.bat b/scripts/AutoPullGitChanges.bat similarity index 100% rename from AutoPullGitChanges.bat rename to scripts/AutoPullGitChanges.bat diff --git a/all_auto_task.py b/scripts/all_auto_task.py similarity index 100% rename from all_auto_task.py rename to scripts/all_auto_task.py diff --git a/auto_cache.py b/scripts/auto_cache.py similarity index 100% rename from auto_cache.py rename to scripts/auto_cache.py diff --git a/auto_realtime.py b/scripts/auto_realtime.py similarity index 100% rename from auto_realtime.py rename to scripts/auto_realtime.py diff --git a/auto_store_non_realtime_SCADA_data.py b/scripts/auto_store_non_realtime_SCADA_data.py similarity index 100% rename from auto_store_non_realtime_SCADA_data.py rename to scripts/auto_store_non_realtime_SCADA_data.py diff --git a/build_pyd.cmd b/scripts/build_pyd.cmd similarity index 100% rename from build_pyd.cmd rename to scripts/build_pyd.cmd diff --git a/build_pyd.py b/scripts/build_pyd.py similarity index 95% rename from build_pyd.py rename to scripts/build_pyd.py index 564f217..fa91129 100644 --- a/build_pyd.py +++ b/scripts/build_pyd.py @@ -17,7 +17,6 @@ setup(ext_modules=cythonize([ "get_current_status.py", "influxdb_api.py", "influxdb_query_SCADA_data.py", - "sensor_placement.py", "simulation.py", "time_api.py", "api/*.py", diff --git a/clean_projects.py b/scripts/clean_projects.py similarity index 54% rename from clean_projects.py rename to scripts/clean_projects.py index e0f0e44..0cb677c 100644 --- a/clean_projects.py +++ b/scripts/clean_projects.py @@ -1,4 +1,4 @@ -from tjnetwork import * +from app.services.tjnetwork import clean_project, delete_project if __name__ == '__main__': clean_project() diff --git a/copy_project.py b/scripts/copy_project.py similarity index 88% rename from copy_project.py rename to scripts/copy_project.py index ae7364c..7cf903d 100644 --- a/copy_project.py +++ b/scripts/copy_project.py @@ -1,5 +1,5 @@ import sys -from tjnetwork import * +from app.services.tjnetwork import copy_project, have_project def main(): argc = len(sys.argv) diff --git a/create_project.py b/scripts/create_project.py similarity index 82% rename from create_project.py rename to scripts/create_project.py index fca7eea..30be5d0 100644 --- a/create_project.py +++ b/scripts/create_project.py @@ -1,5 +1,5 @@ import sys -from tjnetwork import * +from app.services.tjnetwork import read_inp def main(): if len(sys.argv) != 2: diff --git a/create_project_v3.py b/scripts/create_project_v3.py similarity index 82% rename from create_project_v3.py rename to scripts/create_project_v3.py index 818e013..150d460 100644 --- a/create_project_v3.py +++ b/scripts/create_project_v3.py @@ -1,5 +1,5 @@ import sys -from tjnetwork import * +from app.services.tjnetwork import read_inp def main(): if len(sys.argv) != 2: diff --git a/create_template.py b/scripts/create_template.py similarity index 100% rename from create_template.py rename to scripts/create_template.py diff --git a/delete_project.py b/scripts/delete_project.py similarity index 77% rename from delete_project.py rename to scripts/delete_project.py index 8f3d990..5451d5a 100644 --- a/delete_project.py +++ b/scripts/delete_project.py @@ -1,5 +1,5 @@ import sys -from tjnetwork import * +from app.services.tjnetwork import delete_project def main(): if len(sys.argv) != 2: diff --git a/demo.py b/scripts/demo.py similarity index 70% rename from demo.py rename to scripts/demo.py index 2f1e348..c4e3014 100644 --- a/demo.py +++ b/scripts/demo.py @@ -1,4 +1,4 @@ -from tjnetwork import * +from app.services.tjnetwork import list_project, read_inp read_inp("beibeizone","beibeizone.inp") #open_project('beibeizone') #generate_service_area("beibeizone",0.00001) diff --git a/dev.py b/scripts/dev.py similarity index 95% rename from dev.py rename to scripts/dev.py index fb603c1..bda8f47 100644 --- a/dev.py +++ b/scripts/dev.py @@ -1,4 +1,4 @@ -from tjnetwork import * +from app.services.tjnetwork import calculate_service_area, open_project, read_inp p = 'dev' diff --git a/drawpipe.py b/scripts/drawpipe.py similarity index 100% rename from drawpipe.py rename to scripts/drawpipe.py diff --git a/dump_inp.py b/scripts/dump_inp.py similarity index 81% rename from dump_inp.py rename to scripts/dump_inp.py index 1355390..f4d365e 100644 --- a/dump_inp.py +++ b/scripts/dump_inp.py @@ -1,5 +1,5 @@ import sys -from tjnetwork import * +from app.services.tjnetwork import dump_inp def main(): if len(sys.argv) != 2: diff --git a/scripts/encrypt_string.py b/scripts/encrypt_string.py new file mode 100644 index 0000000..eb6e366 --- /dev/null +++ b/scripts/encrypt_string.py @@ -0,0 +1,33 @@ +import os +import sys + +# 将项目根目录添加到 python 路径 +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from app.core.encryption import get_database_encryptor + + +def main() -> int: + plaintext = None + if not sys.stdin.isatty(): + stdin_text = sys.stdin.read() + if stdin_text != "": + plaintext = stdin_text.rstrip("\r\n") + if plaintext is None and len(sys.argv) >= 2: + plaintext = sys.argv[1] + if plaintext is None: + try: + plaintext = input("请输入要加密的文本: ") + except EOFError: + plaintext = "" + if not plaintext.strip(): + print("Error: plaintext string cannot be empty.", file=sys.stderr) + return 1 + + token = get_database_encryptor().encrypt(plaintext) + print(token) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/get_current_status.py b/scripts/get_current_status.py similarity index 95% rename from get_current_status.py rename to scripts/get_current_status.py index 2b63f2b..e64c8a8 100644 --- a/get_current_status.py +++ b/scripts/get_current_status.py @@ -1,4 +1,4 @@ -from tjnetwork import * +from app.services.tjnetwork import api, get_all_service_area_ids, open_project from get_realValue import * from get_hist_data import * import datetime diff --git a/get_current_total_Q.py b/scripts/get_current_total_Q.py similarity index 83% rename from get_current_total_Q.py rename to scripts/get_current_total_Q.py index 69c4bad..b664509 100644 --- a/get_current_total_Q.py +++ b/scripts/get_current_total_Q.py @@ -1,4 +1,3 @@ -from tjnetwork import * from get_realValue import * def get_current_total_Q(): ids=['3489'] diff --git a/get_data.py b/scripts/get_data.py similarity index 77% rename from get_data.py rename to scripts/get_data.py index 090153b..6cfd87d 100644 --- a/get_data.py +++ b/scripts/get_data.py @@ -7,18 +7,19 @@ import csv # get_data 是用来获取 历史数据,也就是非实时数据的接口 # get_realtime 是用来获取 实时数据 + def convert_timestamp_to_beijing_time(timestamp: Union[int, float]) -> datetime: # 将毫秒级时间戳转换为秒级时间戳 timestamp_seconds = timestamp / 1000 # 将时间戳转换为datetime对象 - utc_time = datetime.utcfromtimestamp(timestamp_seconds) + utc_time = datetime.fromtimestamp(timestamp_seconds) # 设定UTC时区 - utc_timezone = pytz.timezone('UTC') + utc_timezone = pytz.timezone("UTC") # 转换为北京时间 - beijing_timezone = pytz.timezone('Asia/Shanghai') + beijing_timezone = pytz.timezone("Asia/Shanghai") beijing_time = utc_time.replace(tzinfo=utc_timezone).astimezone(beijing_timezone) return beijing_time @@ -26,10 +27,10 @@ def convert_timestamp_to_beijing_time(timestamp: Union[int, float]) -> datetime: def beijing_time_to_utc(beijing_time_str: str) -> str: # 定义北京时区 - beijing_timezone = pytz.timezone('Asia/Shanghai') + beijing_timezone = pytz.timezone("Asia/Shanghai") # 将字符串转换为datetime对象 - beijing_time = datetime.strptime(beijing_time_str, '%Y-%m-%d %H:%M:%S') + beijing_time = datetime.strptime(beijing_time_str, "%Y-%m-%d %H:%M:%S") # 本地化时间对象 beijing_time = beijing_timezone.localize(beijing_time) @@ -38,29 +39,31 @@ def beijing_time_to_utc(beijing_time_str: str) -> str: utc_time = beijing_time.astimezone(pytz.utc) # 转换为ISO 8601格式的字符串 - return utc_time.strftime('%Y-%m-%dT%H:%M:%SZ') + return utc_time.strftime("%Y-%m-%dT%H:%M:%SZ") -def get_history_data(ids: str, begin_date: str, end_date: str, downsample: Optional[str]) -> List[Dict[str, Union[str, datetime, int, float]]]: -# def get_history_data(ids: str, begin_date: str, end_date: str, downsample: Optional[str]) -> None: +def get_history_data( + ids: str, begin_date: str, end_date: str, downsample: Optional[str] +) -> List[Dict[str, Union[str, datetime, int, float]]]: + # def get_history_data(ids: str, begin_date: str, end_date: str, downsample: Optional[str]) -> None: # 转换输入的北京时间为UTC时间 begin_date_utc = beijing_time_to_utc(begin_date) end_date_utc = beijing_time_to_utc(end_date) # 数据接口的地址 - url = 'http://183.64.62.100:9057/loong/api/curves/data' + url = "http://183.64.62.100:9057/loong/api/curves/data" # url = 'http://10.101.15.16:9000/loong/api/curves/data' # url_path = 'http://10.101.15.16:9000/loong' # 内网 # 设置 GET 请求的参数 params = { - 'ids': ids, - 'beginDate': begin_date_utc, - 'endDate': end_date_utc, - 'downsample': downsample + "ids": ids, + "beginDate": begin_date_utc, + "endDate": end_date_utc, + "downsample": downsample, } - history_data_list =[] + history_data_list = [] try: # 发送 GET 请求获取数据 @@ -73,24 +76,26 @@ def get_history_data(ids: str, begin_date: str, end_date: str, downsample: Optio # 这里可以对获取到的数据进行进一步处理 # 打印 'mpointId' 和 'mpointName' - for item in data['items']: - mpoint_id = str(item['mpointId']) - mpoint_name = item['mpointName'] + for item in data["items"]: + mpoint_id = str(item["mpointId"]) + mpoint_name = item["mpointName"] # print("mpointId:", item['mpointId']) # print("mpointName:", item['mpointName']) # 打印 'dataDate' 和 'dataValue' - for item_data in item['data']: + for item_data in item["data"]: # 将时间戳转换为北京时间 - beijing_time = convert_timestamp_to_beijing_time(item_data['dataDate']) - data_value = item_data['dataValue'] + beijing_time = convert_timestamp_to_beijing_time( + item_data["dataDate"] + ) + data_value = item_data["dataValue"] # 创建一个字典存储每条数据 data_dict = { - 'time': beijing_time, - 'device_ID': str(mpoint_id), - 'description': mpoint_name, + "time": beijing_time, + "device_ID": str(mpoint_id), + "description": mpoint_name, # 'dataDate (Beijing Time)': beijing_time.strftime('%Y-%m-%d %H:%M:%S'), - 'monitored_value': data_value # 保留原有类型 + "monitored_value": data_value, # 保留原有类型 } history_data_list.append(data_dict) @@ -164,4 +169,4 @@ def get_history_data(ids: str, begin_date: str, end_date: str, downsample: Optio # for data in data_list1: # writer.writerow([data['measurement'], data['mpointId'], data['date'], data['dataValue'], data['datetime']]) # -# print(f"筛选后的数据已保存到 {filtered_csv_file_path}") \ No newline at end of file +# print(f"筛选后的数据已保存到 {filtered_csv_file_path}") diff --git a/get_hist_data.py b/scripts/get_hist_data.py similarity index 54% rename from get_hist_data.py rename to scripts/get_hist_data.py index 3626505..04386e5 100644 --- a/get_hist_data.py +++ b/scripts/get_hist_data.py @@ -8,35 +8,33 @@ def convert_timestamp_to_beijing_time(timestamp): timestamp_seconds = timestamp / 1000 # 将时间戳转换为datetime对象 - utc_time = datetime.utcfromtimestamp(timestamp_seconds) + utc_time = datetime.fromtimestamp(timestamp_seconds) # 设定UTC时区 - utc_timezone = pytz.timezone('UTC') + utc_timezone = pytz.timezone("UTC") # 转换为北京时间 - beijing_timezone = pytz.timezone('Asia/Shanghai') + beijing_timezone = pytz.timezone("Asia/Shanghai") beijing_time = utc_time.replace(tzinfo=utc_timezone).astimezone(beijing_timezone) return beijing_time -def conver_beingtime_to_ucttime(timestr:str): - beijing_time=datetime.strptime(timestr,'%Y-%m-%d %H:%M:%S') - utc_time=beijing_time.astimezone(pytz.utc) - str_utc=utc_time.strftime('%Y-%m-%dT%H:%M:%SZ') - #print(str_utc) + +def conver_beingtime_to_ucttime(timestr: str): + beijing_time = datetime.strptime(timestr, "%Y-%m-%d %H:%M:%S") + utc_time = beijing_time.astimezone(pytz.utc) + str_utc = utc_time.strftime("%Y-%m-%dT%H:%M:%SZ") + # print(str_utc) return str_utc -def get_hist_data(ids, begin_date,end_date)->dict[str,dict[datetime,float]]: + +def get_hist_data(ids, begin_date, end_date) -> dict[str, dict[datetime, float]]: # 数据接口的地址 - url = 'http://183.64.62.100:9057/loong/api/curves/data' + url = "http://183.64.62.100:9057/loong/api/curves/data" # 设置 GET 请求的参数 - params = { - 'ids': ids, - 'beginDate': begin_date, - 'endDate': end_date - } - lst_data={} + params = {"ids": ids, "beginDate": begin_date, "endDate": end_date} + lst_data = {} try: # 发送 GET 请求获取数据 response = requests.get(url, params=params) @@ -48,22 +46,27 @@ def get_hist_data(ids, begin_date,end_date)->dict[str,dict[datetime,float]]: # 这里可以对获取到的数据进行进一步处理 # 打印 'mpointId' 和 'mpointName' - for item in data['items']: - #print("mpointId:", item['mpointId']) - #print("mpointName:", item['mpointName']) + for item in data["items"]: + # print("mpointId:", item['mpointId']) + # print("mpointName:", item['mpointName']) # 打印 'dataDate' 和 'dataValue' - data_seriers={} - for item_data in item['data']: + data_seriers = {} + for item_data in item["data"]: # print("dataDate:", item_data['dataDate']) # 将时间戳转换为北京时间 - beijing_time = convert_timestamp_to_beijing_time(item_data['dataDate']) - print("dataDate (Beijing Time):", beijing_time.strftime('%Y-%m-%d %H:%M:%S')) - print("dataValue:", item_data['dataValue']) + beijing_time = convert_timestamp_to_beijing_time( + item_data["dataDate"] + ) + print( + "dataDate (Beijing Time):", + beijing_time.strftime("%Y-%m-%d %H:%M:%S"), + ) + print("dataValue:", item_data["dataValue"]) print() # 打印空行分隔不同条目 - r=float(item_data['dataValue']) - data_seriers[beijing_time]=r - lst_data[item['mpointId']]=data_seriers + r = float(item_data["dataValue"]) + data_seriers[beijing_time] = r + lst_data[item["mpointId"]] = data_seriers return lst_data else: # 如果请求不成功,打印错误信息 diff --git a/get_realValue.py b/scripts/get_realValue.py similarity index 100% rename from get_realValue.py rename to scripts/get_realValue.py diff --git a/install.py b/scripts/install.py similarity index 100% rename from install.py rename to scripts/install.py diff --git a/main.py b/scripts/main.py similarity index 94% rename from main.py rename to scripts/main.py index f576146..070895c 100644 --- a/main.py +++ b/scripts/main.py @@ -1,11 +1,17 @@ -import asyncio, os, io, json, time, pickle, redis, datetime, logging, threading, uvicorn, multiprocessing, asyncio, shutil, random +import os +import json +import time +import datetime +import logging +import threading +import shutil +import random + from typing import * +from typing import List, Annotated, Optional, Union + from urllib.request import Request -from xml.dom import minicompat -from pydantic import BaseModel -from starlette.responses import FileResponse, JSONResponse -from starlette.middleware.base import BaseHTTPMiddleware -from starlette.types import Receive + from fastapi import ( FastAPI, File, @@ -13,46 +19,300 @@ from fastapi import ( Response, status, Request, - Body, HTTPException, Query, + Depends, + Header, ) from fastapi.responses import PlainTextResponse from fastapi.middleware.gzip import GZipMiddleware -from tjnetwork import * -from multiprocessing import Value -import uvicorn -import msgpack -from run_simulation import run_simulation, run_simulation_ex -from online_Analysis import * from fastapi.middleware.cors import CORSMiddleware -from influxdb_client import ( - InfluxDBClient, - BucketsApi, - WriteApi, - OrganizationsApi, - Point, - QueryApi, -) -from typing import List, Dict + +from starlette.responses import FileResponse, JSONResponse +from contextlib import asynccontextmanager + +from pydantic import BaseModel + +from multiprocessing import Value + +import redis +import msgpack from datetime import datetime, timedelta, timezone -from dateutil import parser -import influxdb_info -import influxdb_api + +# 第三方/自定义模块 +import app.infra.db.influxdb.api as influxdb_api +import app.infra.db.timescaledb as timescaledb +import app.infra.db.postgresql as postgresql import py_linq -import time_api -import simulation -import globals -import os -import logging -import threading -import time -from logging.handlers import TimedRotatingFileHandler -from fastapi import FastAPI, APIRouter, Depends, HTTPException, status, Request -from fastapi.security import OAuth2PasswordBearer -from fastapi import FastAPI, Depends, HTTPException, Header -from typing import Annotated -import project_info +import app.services.time_api as time_api +import app.services.simulation as simulation +import app.services.globals as globals +import app.services.project_info as project_info +from app.infra.db.timescaledb.database import db as tsdb +from app.infra.db.postgresql.database import db as pgdb +from app.algorithms.online_Analysis import * +from app.services.tjnetwork import ( + Any, + ChangeSet, + PIPE_STATUS_OPEN, + VALVES_TYPE_PRV, + add_curve, + add_district_metering_area, + add_junction, + add_label, + add_mixing, + add_pattern, + add_pipe, + add_pump, + add_region, + add_reservoir, + add_scada_device, + add_scada_device_data, + add_scada_element, + add_service_area, + add_source, + add_tank, + add_valve, + add_vertex, + add_virtual_district, + api, + calculate_demand_to_network, + calculate_demand_to_nodes, + calculate_demand_to_region, + calculate_district_metering_area_for_network, + calculate_district_metering_area_for_nodes, + calculate_district_metering_area_for_region, + calculate_service_area, + calculate_virtual_district, + clean_scada_device, + clean_scada_device_data, + clean_scada_element, + close_project, + convert_inp_v3_to_v2, + copy_project, + create_project, + delete_curve, + delete_district_metering_area, + delete_junction, + delete_label, + delete_mixing, + delete_pattern, + delete_pipe, + delete_project, + delete_pump, + delete_region, + delete_reservoir, + delete_scada_device, + delete_scada_device_data, + delete_scada_element, + delete_service_area, + delete_source, + delete_tank, + delete_valve, + delete_virtual_district, + dump_inp, + dump_output, + execute_batch_command, + execute_batch_commands, + execute_redo, + execute_undo, + export_inp, + generate_district_metering_area, + generate_service_area, + generate_sub_district_metering_area, + generate_virtual_district, + get_all_burst_locate_results, + get_all_district_metering_area_ids, + get_all_district_metering_areas, + get_all_extension_data, + get_all_extension_data_keys, + get_all_junctions, + get_all_pipes, + get_all_pumps, + get_all_reservoirs, + get_all_scada_device_ids, + get_all_scada_devices, + get_all_scada_elements, + get_all_scada_info, + get_all_schemes, + get_all_sensor_placements, + get_all_service_areas, + get_all_tanks, + get_all_users, + get_all_valves, + get_all_vertex_links, + get_all_vertices, + get_all_virtual_districts, + get_backdrop, + get_backdrop_schema, + get_control, + get_control_schema, + get_current_operation, + get_curve, + get_curve_schema, + get_curves, + get_demand, + get_demand_schema, + get_district_metering_area, + get_district_metering_area_schema, + get_element_properties, + get_element_properties_with_type, + get_element_type, + get_element_type_value, + get_emitter, + get_emitter_schema, + get_energy, + get_energy_schema, + get_extension_data, + get_junction, + get_junction_schema, + get_label, + get_label_schema, + get_link_properties, + get_link_type, + get_links, + get_major_node_coords, + get_major_pipe_nodes, + get_mixing, + get_mixing_schema, + get_network_link_nodes, + get_network_node_coords, + get_network_pipe_risk_probability_now, + get_node_coord, + get_node_links, + get_node_properties, + get_node_type, + get_nodes, + get_option_v3, + get_option_v3_schema, + get_pattern, + get_pattern_schema, + get_patterns, + get_pipe, + get_pipe_reaction, + get_pipe_reaction_schema, + get_pipe_risk_probability, + get_pipe_risk_probability_geometries, + get_pipe_risk_probability_now, + get_pipe_schema, + get_pipes_risk_probability, + get_pump, + get_pump_energy, + get_pump_energy_schema, + get_pump_schema, + get_quality, + get_quality_schema, + get_reaction, + get_reaction_schema, + get_region, + get_region_schema, + get_reservoir, + get_reservoir_schema, + get_restore_operation, + get_rule, + get_rule_schema, + get_scada_device, + get_scada_device_data, + get_scada_device_data_schema, + get_scada_device_schema, + get_scada_element, + get_scada_element_schema, + get_scada_info, + get_scada_info_schema, + get_scheme, + get_scheme_schema, + get_service_area, + get_service_area_schema, + get_source, + get_source_schema, + get_status, + get_status_schema, + get_tag, + get_tag_schema, + get_tags, + get_tank, + get_tank_reaction, + get_tank_reaction_schema, + get_tank_schema, + get_time, + get_time_schema, + get_title, + get_title_schema, + get_user, + get_user_schema, + get_valve, + get_valve_schema, + get_vertex, + get_vertex_schema, + get_virtual_district, + get_virtual_district_schema, + have_project, + have_snapshot, + have_snapshot_for_current_operation, + have_snapshot_for_operation, + import_inp, + is_curve, + is_junction, + is_link, + is_node, + is_pattern, + is_pipe, + is_project_open, + is_pump, + is_reservoir, + is_tank, + is_valve, + list_project, + list_snapshot, + open_project, + pick_operation, + pick_snapshot, + read_inp, + run_inp, + run_project, + run_project_return_dict, + set_backdrop, + set_control, + set_curve, + set_demand, + set_district_metering_area, + set_emitter, + set_energy, + set_extension_data, + set_junction, + set_label, + set_option_v3, + set_pattern, + set_pipe, + set_pipe_reaction, + set_pump, + set_pump_energy, + set_quality, + set_reaction, + set_region, + set_reservoir, + set_restore_operation, + set_rule, + set_scada_device, + set_scada_device_data, + set_scada_element, + set_service_area, + set_source, + set_status, + set_tag, + set_tank, + set_tank_reaction, + set_time, + set_title, + set_valve, + set_vertex, + set_virtual_district, + sync_with_server, + take_snapshot, + take_snapshot_for_current_operation, + take_snapshot_for_operation, +) + JUNCTION = 0 RESERVOIR = 1 @@ -62,16 +322,16 @@ NODE_COUNT = 0 LINK_COUNT = 2 prjs = [] -inpDir = "C:/inpfiles/" -tmpDir = "C:/tmpfiles/" -proj_name = project_info.name -lockedPrjs = {} +# inpDir = "C:/inpfiles/" +# tmpDir = "C:/tmpfiles/" +# proj_name = project_info.name +# lockedPrjs = {} -if not os.path.exists(inpDir): - os.mkdir(inpDir) +# if not os.path.exists(inpDir): +# os.mkdir(inpDir) -if not os.path.exists(tmpDir): - os.mkdir(tmpDir) +# if not os.path.exists(tmpDir): +# os.mkdir(tmpDir) # 全局依赖项 @@ -113,7 +373,31 @@ async def verify_token(authorization: Annotated[str, Header()] = None): # 全局依赖项 # app = FastAPI(dependencies=[Depends(global_auth)]) -app = FastAPI() +# app = FastAPI() + + +# 生命周期管理器 +@asynccontextmanager +async def lifespan(app: FastAPI): + # 初始化数据库连接池 + tsdb.init_pool() + pgdb.init_pool() + + await tsdb.open() + await pgdb.open() + + open_project(project_info.name) + + yield + # 清理资源 + tsdb.close() + pgdb.close() + + +app = FastAPI(lifespan=lifespan) + +app.include_router(timescaledb.router) +app.include_router(postgresql.router) access_tokens = [] @@ -3120,6 +3404,8 @@ async def fastapi_query_cleaning_scada_data_by_device_id_and_time_range( return influxdb_api.query_cleaning_SCADA_data_by_device_ID_and_timerange( query_ids_list=query_ids, start_time=starttime, end_time=endtime ) + + # 查询到的SCADA模拟数据(从 realtime_simulation bucket 中查找) @app.get("/querysimulationscadadatabydeviceidandtimerange/") async def fastapi_query_simulation_scada_data_by_device_id_and_time_range( @@ -3207,7 +3493,7 @@ async def fastapi_query_all_scheme_all_records( return loaded_dict results = influxdb_api.query_scheme_all_record( - scheme_Type=schemetype, scheme_Name=schemename, query_date=querydate + scheme_type=schemetype, scheme_name=schemename, query_date=querydate ) packed = msgpack.packb(results, default=encode_datetime) redis_client.set(cache_key, packed) @@ -3231,7 +3517,7 @@ async def fastapi_query_all_scheme_all_records_property( all_results = msgpack.unpackb(data, object_hook=decode_datetime) else: all_results = influxdb_api.query_scheme_all_record( - scheme_Type=schemetype, scheme_Name=schemename, query_date=querydate + scheme_type=schemetype, scheme_name=schemename, query_date=querydate ) packed = msgpack.packb(all_results, default=encode_datetime) redis_client.set(cache_key, packed) @@ -3444,6 +3730,7 @@ async def fastapi_run_simulation_manually_by_date( item["name"], region_result ) ) + ( globals.source_outflow_region_patterns, globals.realtime_region_pipe_flow_and_demand_patterns, @@ -3460,6 +3747,7 @@ async def fastapi_run_simulation_manually_by_date( item["name"], base_date, item["start_time"], item["duration"] ) ) + thread.start() thread.join() # 等待线程完成 @@ -3557,7 +3845,7 @@ class BurstAnalysis(BaseModel): modify_fixed_pump_pattern: Optional[dict[str, list]] = None modify_variable_pump_pattern: Optional[dict[str, list]] = None modify_valve_opening: Optional[dict[str, float]] = None - scheme_Name: Optional[str] = None + scheme_name: Optional[str] = None @app.post("/burst_analysis/") @@ -3580,7 +3868,7 @@ async def fastapi_burst_analysis(data: BurstAnalysis) -> str: modify_fixed_pump_pattern=item["modify_fixed_pump_pattern"], modify_variable_pump_pattern=item["modify_variable_pump_pattern"], modify_valve_opening=item["modify_valve_opening"], - scheme_Name=item["scheme_Name"], + scheme_name=item["scheme_name"], ) # os.rename(filename2, filename) @@ -3588,7 +3876,7 @@ async def fastapi_burst_analysis(data: BurstAnalysis) -> str: # 将 时间转换成日期,然后缓存这个计算结果 # 缓存key: burst_analysis__ global redis_client - schemename = data.scheme_Name + schemename = data.scheme_name print(data.modify_pattern_start_time) @@ -3599,7 +3887,7 @@ async def fastapi_burst_analysis(data: BurstAnalysis) -> str: cache_key = f"queryallschemeallrecords_burst_Analysis_{schemename}_{querydate}" data = redis_client.get(cache_key) if not data: - results = influxdb_api.query_scheme_all_record("burst_Analysis", scheme_Name=schemename, query_date=querydate) + results = influxdb_api.query_scheme_all_record("burst_Analysis", scheme_name=schemename, query_date=querydate) packed = msgpack.packb(results, default=encode_datetime) redis_client.set(cache_key, packed) """ @@ -3682,8 +3970,9 @@ async def fastapi_contaminant_simulation( start_time: str, source: str, concentration: float, - duration: int = 900, + duration: int, pattern: str = None, + scheme_name: str = None, ) -> str: filename = "c:/lock.simulation" filename2 = "c:/lock.simulation2" @@ -4207,8 +4496,8 @@ async def get_dict(item: Item): if __name__ == "__main__": # uvicorn.run(app, host="0.0.0.0", port=8000) # url='http://127.0.0.1:8000/valve_close_analysis?network=beibeizone&start_time=2024-04-01T08:00:00Z&valve_IDs=GSD2307192058577780A3287D78&valve_IDs=GSD2307192058572E953B707226(S2)&duration=1800' - # url='http://127.0.0.1:8000/burst_analysis?network=beibeizone&start_time=2024-04-01T08:00:00Z&burst_ID=ZBBGXSZW000001&duration=1800' - url = "http://192.168.1.36:8000/queryallschemeallrecords/?schemename=Fangan0817114448&querydate=2025-08-13&schemetype=burst_Analysis" + url = "http://127.0.0.1:8000/burst_analysis?network=beibeizone&start_time=2024-04-01T08:00:00Z&burst_ID=ZBBGXSZW000001&duration=1800" + # url = "http://192.168.1.36:8000/queryallschemeallrecords/?schemename=Fangan0817114448&querydate=2025-08-13&schemetype=burst_Analysis" # response = Request.get(url) import requests diff --git a/scripts/main_api_endpoints.md b/scripts/main_api_endpoints.md new file mode 100644 index 0000000..89e2132 --- /dev/null +++ b/scripts/main_api_endpoints.md @@ -0,0 +1,398 @@ +# API Endpoints (scripts/main.py) + +Non-commented FastAPI routes defined in `scripts/main.py`. + +- `POST /login/` +- `GET /getallextensiondatakeys/` +- `GET /getallextensiondata/` +- `GET /getextensiondata/` +- `POST /setextensiondata` +- `GET /listprojects/` +- `GET /haveproject/` +- `POST /createproject/` +- `POST /deleteproject/` +- `GET /isprojectopen/` +- `POST /openproject/` +- `POST /closeproject/` +- `POST /copyproject/` +- `POST /importinp/` +- `GET /exportinp/` +- `POST /readinp/` +- `GET /dumpinp/` +- `GET /runproject/` +- `GET /runprojectreturndict/` +- `GET /runinp/` +- `GET /dumpoutput/` +- `GET /isprojectlocked/` +- `GET /isprojectlockedbyme/` +- `POST /lockproject/` +- `POST /unlockproject/` +- `GET /getcurrentoperationid/` +- `POST /undo/` +- `POST /redo/` +- `GET /getsnapshots/` +- `GET /havesnapshot/` +- `GET /havesnapshotforoperation/` +- `GET /havesnapshotforcurrentoperation/` +- `POST /takesnapshotforoperation/` +- `POST takenapshotforcurrentoperation` +- `POST /takesnapshot/` +- `POST /picksnapshot/` +- `POST /pickoperation/` +- `GET /syncwithserver/` +- `POST /batch/` +- `POST /compressedbatch/` +- `GET /getrestoreoperation/` +- `POST /setrestoreoperation/` +- `GET /isnode/` +- `GET /isjunction/` +- `GET /isreservoir/` +- `GET /istank/` +- `GET /islink/` +- `GET /ispipe/` +- `GET /ispump/` +- `GET /isvalve/` +- `GET /getnodetype/` +- `GET /getlinktype/` +- `GET /getelementtype/` +- `GET /getelementtypevalue/` +- `GET /iscurve/` +- `GET /ispattern/` +- `GET /getnodes/` +- `GET /getlinks/` +- `GET /getcurves/` +- `GET /getpatterns/` +- `GET /getnodelinks/` +- `GET /getnodeproperties/` +- `GET /getlinkproperties/` +- `GET /getscadaproperties/` +- `GET /getallscadaproperties/` +- `GET /getelementpropertieswithtype/` +- `GET /getelementproperties/` +- `GET /gettitleschema/` +- `GET /gettitle/` +- `GET /settitle/` +- `GET /getjunctionschema` +- `POST /addjunction/` +- `POST /deletejunction/` +- `GET /getjunctionelevation/` +- `GET /getjunctionx/` +- `GET /getjunctiony/` +- `GET /getjunctioncoord/` +- `GET /getjunctiondemand/` +- `GET /getjunctionpattern/` +- `POST /setjunctionelevation/` +- `POST /setjunctionx/` +- `POST /setjunctiony/` +- `POST /setjunctioncoord/` +- `POST /setjunctiondemand/` +- `POST /setjunctionpattern/` +- `GET /getjunctionproperties/` +- `GET /getalljunctionproperties/` +- `POST /setjunctionproperties/` +- `GET /getreservoirschema` +- `POST /addreservoir/` +- `POST /deletereservoir/` +- `GET /getreservoirhead/` +- `GET /getreservoirpattern/` +- `GET /getreservoirx/` +- `GET /getreservoiry/` +- `GET /getreservoircoord/` +- `POST /setreservoirhead/` +- `POST /setreservoirpattern/` +- `POST /setreservoirx/` +- `POST /setreservoirx/` +- `POST /setreservoircoord/` +- `GET /getreservoirproperties/` +- `GET /getallreservoirproperties/` +- `POST /setreservoirproperties/` +- `GET /gettankschema` +- `POST /addtank/` +- `POST /deletetank/` +- `GET /gettankelevation/` +- `GET /gettankinitlevel/` +- `GET /gettankminlevel/` +- `GET /gettankmaxlevel/` +- `GET /gettankdiameter/` +- `GET /gettankminvol/` +- `GET /gettankvolcurve/` +- `GET /gettankoverflow/` +- `GET /gettankx/` +- `GET /gettanky/` +- `GET /gettankcoord/` +- `POST /settankelevation/` +- `POST /settankinitlevel/` +- `POST /settankminlevel/` +- `POST /settankmaxlevel/` +- `POST settankdiameter//` +- `POST /settankminvol/` +- `POST /settankvolcurve/` +- `POST /settankoverflow/` +- `POST /settankx/` +- `POST /settanky/` +- `POST /settankcoord/` +- `GET /gettankproperties/` +- `GET /getalltankproperties/` +- `POST /settankproperties/` +- `GET /getpipeschema` +- `POST /addpipe/` +- `POST /deletepipe/` +- `GET /getpipenode1/` +- `GET /getpipenode2/` +- `GET /getpipelength/` +- `GET /getpipediameter/` +- `GET /getpiperoughness/` +- `GET /getpipeminorloss/` +- `GET /getpipestatus/` +- `POST /setpipenode1/` +- `POST /setpipenode2/` +- `POST /setpipelength/` +- `POST /setpipediameter/` +- `POST /setpiperoughness/` +- `POST /setpipeminorloss/` +- `POST /setpipestatus/` +- `GET /getpipeproperties/` +- `GET /getallpipeproperties/` +- `POST /setpipeproperties/` +- `GET /getpumpschema` +- `POST /addpump/` +- `POST /deletepump/` +- `GET /getpumpnode1/` +- `GET /getpumpnode2/` +- `POST /setpumpnode1/` +- `POST /setpumpnode2/` +- `GET /getpumpproperties/` +- `GET /getallpumpproperties/` +- `POST /setpumpproperties/` +- `GET /getvalveschema` +- `POST /addvalve/` +- `POST /deletevalve/` +- `GET /getvalvenode1/` +- `GET /getvalvenode2/` +- `GET /getvalvediameter/` +- `GET /getvalvetype/` +- `GET /getvalvesetting/` +- `GET /getvalveminorloss/` +- `POST /setvalvenode1/` +- `POST /setvalvenode2/` +- `POST /setvalvenodediameter/` +- `POST /setvalvetype/` +- `POST /setvalvesetting/` +- `GET /getvalveproperties/` +- `GET /getallvalveproperties/` +- `POST /setvalveproperties/` +- `POST /deletenode/` +- `POST /deletelink/` +- `GET /gettagschema/` +- `GET /gettag/` +- `GET /gettags/` +- `POST /settag/` +- `GET /getdemandschema` +- `GET /getdemandproperties/` +- `POST /setdemandproperties/` +- `GET /getstatusschema` +- `GET /getstatus/` +- `POST /setstatus/` +- `GET /getpatternschema` +- `POST /addpattern/` +- `POST /deletepattern/` +- `GET /getpatternproperties/` +- `POST /setpatternproperties/` +- `GET /getcurveschema` +- `POST /addcurve/` +- `POST /deletecurve/` +- `GET /getcurveproperties/` +- `POST /setcurveproperties/` +- `GET /getcontrolschema/` +- `GET /getcontrolproperties/` +- `POST /setcontrolproperties/` +- `GET /getruleschema/` +- `GET /getruleproperties/` +- `POST /setruleproperties/` +- `GET /getenergyschema/` +- `GET /getenergyproperties/` +- `POST /setenergyproperties/` +- `GET /getpumpenergyschema/` +- `GET /getpumpenergyproperties//` +- `GET /setpumpenergyproperties//` +- `GET /getemitterschema` +- `GET /getemitterproperties/` +- `POST /setemitterproperties/` +- `GET /getqualityschema/` +- `GET /getqualityproperties/` +- `POST /setqualityproperties/` +- `GET /getsourcechema/` +- `GET /getsource/` +- `POST /setsource/` +- `POST /addsource/` +- `POST /deletesource/` +- `GET /getreactionschema/` +- `GET /getreaction/` +- `POST /setreaction/` +- `GET /getpipereactionschema/` +- `GET /getpipereaction/` +- `POST /setpipereaction/` +- `GET /gettankreactionschema/` +- `GET /gettankreaction/` +- `POST /settankreaction/` +- `GET /getmixingschema/` +- `GET /getmixing/` +- `POST /setmixing/` +- `POST /addmixing/` +- `POST /deletemixing/` +- `GET /gettimeschema` +- `GET /gettimeproperties/` +- `POST /settimeproperties/` +- `GET /getoptionschema/` +- `GET /getoptionproperties/` +- `POST /setoptionproperties/` +- `GET /getnodecoord/` +- `GET /getnetworkgeometries/` +- `GET /getmajornodecoords/` +- `GET /getnetworkinextent/` +- `GET /getnetworklinknodes/` +- `GET /getmajorpipenodes/` +- `GET /getvertexschema/` +- `GET /getvertexproperties/` +- `POST /setvertexproperties/` +- `POST /addvertex/` +- `POST /deletevertex/` +- `GET /getallvertexlinks/` +- `GET /getallvertices/` +- `GET /getlabelschema/` +- `GET /getlabelproperties/` +- `POST /setlabelproperties/` +- `POST /addlabel/` +- `POST /deletelabel/` +- `GET /getbackdropschema/` +- `GET /getbackdropproperties/` +- `POST /setbackdropproperties/` +- `GET /getscadadeviceschema/` +- `GET /getscadadevice/` +- `POST /setscadadevice/` +- `POST /addscadadevice/` +- `POST /deletescadadevice/` +- `POST /cleanscadadevice/` +- `GET /getallscadadeviceids/` +- `GET /getallscadadevices/` +- `GET /getscadadevicedataschema/` +- `GET /getscadadevicedata/` +- `POST /setscadadevicedata/` +- `POST /addscadadevicedata/` +- `POST /deletescadadevicedata/` +- `POST /cleanscadadevicedata/` +- `GET /getscadaelementschema/` +- `GET /getscadaelements/` +- `GET /getscadaelement/` +- `POST /setscadaelement/` +- `POST /addscadaelement/` +- `POST /deletescadaelement/` +- `POST /cleanscadaelement/` +- `GET /getregionschema/` +- `GET /getregion/` +- `POST /setregion/` +- `POST /addregion/` +- `POST /deleteregion/` +- `GET /calculatedistrictmeteringareafornodes/` +- `GET /calculatedistrictmeteringareaforregion/` +- `GET /calculatedistrictmeteringareafornetwork/` +- `GET /getdistrictmeteringareaschema/` +- `GET /getdistrictmeteringarea/` +- `POST /setdistrictmeteringarea/` +- `POST /adddistrictmeteringarea/` +- `POST /deletedistrictmeteringarea/` +- `GET /getalldistrictmeteringareaids/` +- `GET /getalldistrictmeteringareas/` +- `POST /generatedistrictmeteringarea/` +- `POST /generatesubdistrictmeteringarea/` +- `GET /calculateservicearea/` +- `GET /getserviceareaschema/` +- `GET /getservicearea/` +- `POST /setservicearea/` +- `POST /addservicearea/` +- `POST /deleteservicearea/` +- `GET /getallserviceareas/` +- `POST /generateservicearea/` +- `GET /calculatevirtualdistrict/` +- `GET /getvirtualdistrictschema/` +- `GET /getvirtualdistrict/` +- `POST /setvirtualdistrict/` +- `POST /addvirtualdistrict/` +- `POST /deletevirtualdistrict/` +- `GET /getallvirtualdistrict/` +- `POST /generatevirtualdistrict/` +- `GET /calculatedemandtonodes/` +- `GET /calculatedemandtoregion/` +- `GET /calculatedemandtonetwork/` +- `GET /getscadainfoschema/` +- `GET /getscadainfo/` +- `GET /getallscadainfo/` +- `GET /getuserschema/` +- `GET /getuser/` +- `GET /getallusers/` +- `GET /getschemeschema/` +- `GET /getscheme/` +- `GET /getallschemes/` +- `GET /getpiperiskprobabilitynow/` +- `GET /getpiperiskprobability/` +- `GET /getpipesriskprobability/` +- `GET /getnetworkpiperiskprobabilitynow/` +- `GET /getpiperiskprobabilitygeometries/` +- `GET /getallsensorplacements/` +- `GET /getallburstlocateresults/` +- `POST /uploadinp/` +- `GET /downloadinp/` +- `GET /convertv3tov2/` +- `GET /getjson/` +- `GET /getrealtimedata/` +- `GET /getsimulationresult/` +- `GET /querynodelatestrecordbyid/` +- `GET /querylinklatestrecordbyid/` +- `GET /queryscadalatestrecordbyid/` +- `GET /queryallrecordsbytime/` +- `GET /queryallrecordsbytimeproperty/` +- `GET /queryallschemerecordsbytimeproperty/` +- `GET /querysimulationrecordsbyidtime/` +- `GET /queryschemesimulationrecordsbyidtime/` +- `GET /queryallrecordsbydate/` +- `GET /queryallrecordsbytimerange/` +- `GET /queryallrecordsbydatewithtype/` +- `GET /queryallrecordsbyidsdatetype/` +- `GET /queryallrecordsbydateproperty/` +- `GET /querynodecurvebyidpropertydaterange/` +- `GET /querylinkcurvebyidpropertydaterange/` +- `GET /queryscadadatabydeviceidandtime/` +- `GET /queryscadadatabydeviceidandtimerange/` +- `GET /queryfillingscadadatabydeviceidandtimerange/` +- `GET /querycleaningscadadatabydeviceidandtimerange/` +- `GET /querysimulationscadadatabydeviceidandtimerange/` +- `GET /querycleanedscadadatabydeviceidandtimerange/` +- `GET /queryscadadatabydeviceidanddate/` +- `GET /queryallscadarecordsbydate/` +- `GET /queryallschemeallrecords/` +- `GET /queryschemeallrecordsproperty/` +- `POST /clearrediskey/` +- `POST /clearrediskeys/` +- `POST /clearallredis/` +- `GET /queryredis/` +- `GET /queryinfluxdbbuckets/` +- `GET /queryinfluxdbbucketmeasurements/` +- `POST /download_history_data_manually/` +- `POST /runsimulationmanuallybydate/` +- `POST /burst_analysis/` +- `GET /valve_close_analysis/` +- `GET /flushing_analysis/` +- `GET /contaminant_simulation/` +- `GET /age_analysis/` +- `POST /scheduling_analysis/` +- `POST /pressure_regulation/` +- `POST /project_management/` +- `POST /network_project/` +- `POST /daily_scheduling_analysis/` +- `POST /network_update/` +- `POST /pump_failure/` +- `POST /pressure_sensor_placement_sensitivity/` +- `POST /pressure_sensor_placement_kmeans/` +- `POST /sensorplacementscheme/create` +- `POST /scadadevicedatacleaning/` +- `POST /test_dict/` diff --git a/scripts/missing_api_endpoints.md b/scripts/missing_api_endpoints.md new file mode 100644 index 0000000..d0410e4 --- /dev/null +++ b/scripts/missing_api_endpoints.md @@ -0,0 +1,26 @@ +# Missing API Endpoints + +- Legacy endpoints checked: 392 +- Current endpoints found: 401 +- Missing endpoints: 17 + +Note: Current endpoints are defined under app/api and are typically served with the /api/v1 prefix. + +## Missing endpoints (legacy present, current missing) +- `GET /age_analysis/` +- `GET /contaminant_simulation/` +- `GET /flushing_analysis/` +- `GET /valve_close_analysis/` +- `POST /burst_analysis/` +- `POST /daily_scheduling_analysis/` +- `POST /network_project/` +- `POST /network_update/` +- `POST /pressure_regulation/` +- `POST /pressure_sensor_placement_kmeans/` +- `POST /pressure_sensor_placement_sensitivity/` +- `POST /project_management/` +- `POST /pump_failure/` +- `POST /runsimulationmanuallybydate/` +- `POST /scadadevicedatacleaning/` +- `POST /scheduling_analysis/` +- `POST /sensorplacementscheme/create` diff --git a/online_Analysis.py b/scripts/online_Analysis.py similarity index 54% rename from online_Analysis.py rename to scripts/online_Analysis.py index 729d808..bcf4c2e 100644 --- a/online_Analysis.py +++ b/scripts/online_Analysis.py @@ -1,9 +1,39 @@ import os -from tjnetwork import * -from api.project import CopyProjectEx -from run_simulation import run_simulation_ex, from_clock_to_seconds_2 +from app.services.tjnetwork import ( + ChangeSet, + OPTION_DEMAND_MODEL_PDA, + OPTION_QUALITY_CHEMICAL, + SOURCE_TYPE_CONCEN, + add_pattern, + add_source, + close_project, + copy_project, + delete_project, + dump_inp, + get_demand, + get_emitter, + get_node_links, + get_option, + get_pattern, + get_pipe, + get_source, + get_tank, + get_time, + have_project, + is_junction, + is_project_open, + open_project, + read_inp, + set_demand, + set_emitter, + set_option, + set_source, + set_time, +) +from app.native.wndb.project import copy_project +from app.algorithms.simulation.runner import run_simulation_ex, from_clock_to_seconds_2 from math import sqrt, pi -from epanet.epanet import Output +from app.infra.epanet.epanet import Output import json from datetime import datetime import time @@ -13,32 +43,33 @@ from psycopg import sql import pandas as pd import csv import chardet -import simulation +import app.services.simulation as simulation import geopandas as gpd from sqlalchemy import create_engine import ast -import sensitivity -import project_info -import api_ex.kmeans_sensor -import api_ex.Fdataclean -import api_ex.Pdataclean -from api.postgresql_info import get_pgconn_string +import app.services.project_info as project_info +import app.algorithms.sensor.kmeans as kmeans_sensor +import app.algorithms.cleaning.flow as flow_data_clean +import app.algorithms.cleaning.pressure as pressure_data_clean +import app.algorithms.sensor.sensitivity as sensitivity +from app.core.config import get_pgconn_string + ############################################################ # burst analysis 01 ############################################################ -def convert_to_local_unit(proj:str,emitters:float)->float: +def convert_to_local_unit(proj: str, emitters: float) -> float: open_project(proj) - proj_opt=get_option(proj) - str_unit=proj_opt.get('UNITS') + proj_opt = get_option(proj) + str_unit = proj_opt.get("UNITS") - if str_unit == 'CMH': + if str_unit == "CMH": return emitters * 3.6 - elif str_unit == 'LPS': + elif str_unit == "LPS": return emitters - elif str_unit == 'CMS': + elif str_unit == "CMS": return emitters / 1000.0 - elif str_unit == 'MGD': + elif str_unit == "MGD": return emitters * 0.0438126 # Unknown unit: log and return original value @@ -46,10 +77,17 @@ def convert_to_local_unit(proj:str,emitters:float)->float: return emitters -def burst_analysis(name: str, modify_pattern_start_time: str, burst_ID: list | str = None, burst_size: list | float | int = None, - modify_total_duration: int=900, modify_fixed_pump_pattern: dict[str, list] = None, - modify_variable_pump_pattern: dict[str, list] = None, modify_valve_opening: dict[str, float] = None, - scheme_Name: str = None) -> None: +def burst_analysis( + name: str, + modify_pattern_start_time: str, + burst_ID: list | str = None, + burst_size: list | float | int = None, + modify_total_duration: int = 900, + modify_fixed_pump_pattern: dict[str, list] = None, + modify_variable_pump_pattern: dict[str, list] = None, + modify_valve_opening: dict[str, float] = None, + scheme_name: str = None, +) -> None: """ 爆管模拟 :param name: 模型名称,数据库中对应的名字 @@ -60,7 +98,7 @@ def burst_analysis(name: str, modify_pattern_start_time: str, burst_ID: list | s :param modify_fixed_pump_pattern: dict中包含多个水泵模式,str为工频水泵的id,list为修改后的pattern :param modify_variable_pump_pattern: dict中包含多个水泵模式,str为变频水泵的id,list为修改后的pattern :param modify_valve_opening: dict中包含多个阀门开启度,str为阀门的id,float为修改后的阀门开启度 - :param scheme_Name: 方案名称 + :param scheme_name: 方案名称 :return: """ scheme_detail: dict = { @@ -71,68 +109,87 @@ def burst_analysis(name: str, modify_pattern_start_time: str, burst_ID: list | s "modify_variable_pump_pattern": modify_variable_pump_pattern, "modify_valve_opening": modify_valve_opening, } - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'burst_Anal_{name}' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"burst_Anal_{name}" if have_project(new_name): if is_project_open(new_name): close_project(new_name) delete_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - simulation.run_simulation(name=new_name, simulation_type='manually_temporary', modify_pattern_start_time=modify_pattern_start_time) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") + simulation.run_simulation( + name=new_name, + simulation_type="manually_temporary", + modify_pattern_start_time=modify_pattern_start_time, + ) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) ##step 1 set the emitter coefficient of end node of busrt pipe if isinstance(burst_ID, list): if (burst_size is not None) and (type(burst_size) is not list): - return json.dumps('Type mismatch.') + return json.dumps("Type mismatch.") elif isinstance(burst_ID, str): burst_ID = [burst_ID] if burst_size is not None: if isinstance(burst_size, float) or isinstance(burst_size, int): burst_size = [burst_size] else: - return json.dumps('Type mismatch.') + return json.dumps("Type mismatch.") else: - return json.dumps('Type mismatch.') + return json.dumps("Type mismatch.") if burst_size is None: burst_size = [-1] * len(burst_ID) elif len(burst_size) < len(burst_ID): burst_size += [-1] * (len(burst_ID) - len(burst_size)) elif len(burst_size) > len(burst_ID): # burst_size = burst_size[:len(burst_ID)] - return json.dumps('Length mismatch.') + return json.dumps("Length mismatch.") for burst_ID_, burst_size_ in zip(burst_ID, burst_size): pipe = get_pipe(new_name, burst_ID_) - str_start_node = pipe['node1'] - str_end_node = pipe['node2'] - d_pipe = pipe['diameter'] / 1000.0 + str_start_node = pipe["node1"] + str_end_node = pipe["node2"] + d_pipe = pipe["diameter"] / 1000.0 if burst_size_ <= 0: burst_size_ = 3.14 * d_pipe * d_pipe / 4 / 8 else: burst_size_ = burst_size_ / 10000 - emitter_coeff = 0.65 * burst_size_ * sqrt(19.6) * 1000#1/8开口面积作为coeff,单位 L/S - emitter_coeff =convert_to_local_unit(new_name, emitter_coeff) - emitter_node = '' + emitter_coeff = ( + 0.65 * burst_size_ * sqrt(19.6) * 1000 + ) # 1/8开口面积作为coeff,单位 L/S + emitter_coeff = convert_to_local_unit(new_name, emitter_coeff) + emitter_node = "" if is_junction(new_name, str_end_node): emitter_node = str_end_node elif is_junction(new_name, str_start_node): emitter_node = str_start_node old_emitter = get_emitter(new_name, emitter_node) - if(old_emitter != None): - old_emitter['coefficient'] = emitter_coeff #爆管的emitter coefficient设置 + if old_emitter != None: + old_emitter["coefficient"] = emitter_coeff # 爆管的emitter coefficient设置 else: - old_emitter = {'junction': emitter_node, 'coefficient': emitter_coeff} + old_emitter = {"junction": emitter_node, "coefficient": emitter_coeff} new_emitter = ChangeSet() new_emitter.append(old_emitter) set_emitter(new_name, new_emitter) - #step 2. run simulation + # step 2. run simulation # 涉及关阀计算,可能导致关阀后仍有流量,改为压力驱动PDA options = get_option(new_name) - options['DEMAND MODEL'] = OPTION_DEMAND_MODEL_PDA - options['REQUIRED PRESSURE'] = '10.0000' + options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA + options["REQUIRED PRESSURE"] = "10.0000" cs_options = ChangeSet() cs_options.append(options) set_option(new_name, cs_options) @@ -147,48 +204,78 @@ def burst_analysis(name: str, modify_pattern_start_time: str, burst_ID: list | s # modify_pump_pattern=modify_pump_pattern, # valve_control=valve_control, # downloading_prohibition=True) - simulation.run_simulation(name=new_name, simulation_type='extended', modify_pattern_start_time=modify_pattern_start_time, - modify_total_duration=modify_total_duration, modify_fixed_pump_pattern=modify_fixed_pump_pattern, - modify_variable_pump_pattern=modify_variable_pump_pattern, modify_valve_opening=modify_valve_opening, - scheme_Type='burst_Analysis', scheme_Name=scheme_Name) - #step 3. restore the base model status + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + modify_fixed_pump_pattern=modify_fixed_pump_pattern, + modify_variable_pump_pattern=modify_variable_pump_pattern, + modify_valve_opening=modify_valve_opening, + scheme_type="burst_Analysis", + scheme_name=scheme_name, + ) + # step 3. restore the base model status # execute_undo(name) #有疑惑 if is_project_open(new_name): close_project(new_name) delete_project(new_name) # return result - store_scheme_info(name=name, scheme_name=scheme_Name, scheme_type='burst_Analysis', username='admin', - scheme_start_time=modify_pattern_start_time, scheme_detail=scheme_detail) - + store_scheme_info( + name=name, + scheme_name=scheme_name, + scheme_type="burst_Analysis", + username="admin", + scheme_start_time=modify_pattern_start_time, + scheme_detail=scheme_detail, + ) ############################################################ # valve closing analysis 02 ############################################################ -def valve_close_analysis(name: str, modify_pattern_start_time: str, modify_total_duration: int = 900, - modify_valve_opening: dict[str, float] = None, scheme_Name: str = None) -> None: +def valve_close_analysis( + name: str, + modify_pattern_start_time: str, + modify_total_duration: int = 900, + modify_valve_opening: dict[str, float] = None, + scheme_name: str = None, +) -> None: """ 关阀模拟 :param name: 模型名称,数据库中对应的名字 :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' :param modify_total_duration: 模拟总历时,秒 :param modify_valve_opening: dict中包含多个阀门开启度,str为阀门的id,float为修改后的阀门开启度 - :param scheme_Name: 方案名称 + :param scheme_name: 方案名称 :return: """ - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'valve_close_Anal_{name}' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"valve_close_Anal_{name}" if have_project(new_name): if is_project_open(new_name): close_project(new_name) delete_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") - #step 1. change the valves status to 'closed' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + # step 1. change the valves status to 'closed' # for valve in valves: # if not is_valve(new_name,valve): # result='ID:{}is not a valve type'.format(valve) @@ -198,20 +285,26 @@ def valve_close_analysis(name: str, modify_pattern_start_time: str, modify_total # status['status']='CLOSED' # cs.append(status) # set_status(new_name,cs) - #step 2. run simulation + # step 2. run simulation # 涉及关阀计算,可能导致关阀后仍有流量,改为压力驱动PDA options = get_option(new_name) - options['DEMAND MODEL'] = OPTION_DEMAND_MODEL_PDA - options['REQUIRED PRESSURE'] = '20.0000' + options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA + options["REQUIRED PRESSURE"] = "20.0000" cs_options = ChangeSet() cs_options.append(options) set_option(new_name, cs_options) # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time, modify_total_duration, # downloading_prohibition=True) - simulation.run_simulation(name=new_name, simulation_type='extended', modify_pattern_start_time=modify_pattern_start_time, - modify_total_duration=modify_total_duration, modify_valve_opening=modify_valve_opening, - scheme_Type='valve_close_Analysis', scheme_Name=scheme_Name) - #step 3. restore the base model + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + modify_valve_opening=modify_valve_opening, + scheme_type="valve_close_Analysis", + scheme_name=scheme_name, + ) + # step 3. restore the base model # for valve in valves: # execute_undo(name) if is_project_open(new_name): @@ -222,11 +315,17 @@ def valve_close_analysis(name: str, modify_pattern_start_time: str, modify_total ############################################################ # flushing analysis 03 -#Pipe_Flushing_Analysis(prj_name,date_time, Valve_id_list, Drainage_Node_Id, Flushing_flow[opt], Flushing_duration[opt])->out_file:string +# Pipe_Flushing_Analysis(prj_name,date_time, Valve_id_list, Drainage_Node_Id, Flushing_flow[opt], Flushing_duration[opt])->out_file:string ############################################################ -def flushing_analysis(name: str, modify_pattern_start_time: str, modify_total_duration: int = 900, - modify_valve_opening: dict[str, float] = None, drainage_node_ID: str = None, - flushing_flow: float = 0, scheme_Name: str = None) -> None: +def flushing_analysis( + name: str, + modify_pattern_start_time: str, + modify_total_duration: int = 900, + modify_valve_opening: dict[str, float] = None, + drainage_node_ID: str = None, + flushing_flow: float = 0, + scheme_name: str = None, +) -> None: """ 管道冲洗模拟 :param name: 模型名称,数据库中对应的名字 @@ -235,26 +334,39 @@ def flushing_analysis(name: str, modify_pattern_start_time: str, modify_total_du :param modify_valve_opening: dict中包含多个阀门开启度,str为阀门的id,float为修改后的阀门开启度 :param drainage_node_ID: 冲洗排放口所在节点ID :param flushing_flow: 冲洗水量,传入参数单位为m3/h - :param scheme_Name: 方案名称 + :param scheme_name: 方案名称 :return: """ - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'flushing_Anal_{name}' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"flushing_Anal_{name}" if have_project(new_name): if is_project_open(new_name): close_project(new_name) delete_project(new_name) # if is_project_open(name): # close_project(name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") - if not is_junction(new_name,drainage_node_ID): - return 'Wrong Drainage node type' - #step 1. change the valves status to 'closed' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + if not is_junction(new_name, drainage_node_ID): + return "Wrong Drainage node type" + # step 1. change the valves status to 'closed' # for valve, valve_k in zip(valves, valves_k): # cs=ChangeSet() # status=get_status(new_name,valve) @@ -267,132 +379,165 @@ def flushing_analysis(name: str, modify_pattern_start_time: str, modify_total_du # cs.append(status) # set_status(new_name,cs) units = get_option(new_name) - #step 2. set the emitter coefficient of drainage node or add flush flow to the drainage node - emitter_demand=get_demand(new_name,drainage_node_ID) + # step 2. set the emitter coefficient of drainage node or add flush flow to the drainage node + emitter_demand = get_demand(new_name, drainage_node_ID) cs = ChangeSet() if flushing_flow > 0: - for r in emitter_demand['demands']: - if units == 'LPS': - r['demand'] += (flushing_flow/3.6) - elif units == 'CMH': - r['demand'] += flushing_flow + for r in emitter_demand["demands"]: + if units == "LPS": + r["demand"] += flushing_flow / 3.6 + elif units == "CMH": + r["demand"] += flushing_flow cs.append(emitter_demand) - set_demand(new_name,cs) + set_demand(new_name, cs) else: - pipes=get_node_links(new_name,drainage_node_ID) - flush_diameter=50 + pipes = get_node_links(new_name, drainage_node_ID) + flush_diameter = 50 for pipe in pipes: - d=get_pipe(new_name,pipe)['diameter'] - if flush_diameter None: +def contaminant_simulation( + name: str, + modify_pattern_start_time: str, # 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' + modify_total_duration: int = 900, # 模拟总历时,秒 + source: str = None,# 污染源节点ID + concentration: float = None, # 污染源浓度,单位mg/L + source_pattern: str = None, # 污染源时间变化模式名称 + scheme_name: str = None, +) -> None: """ 污染模拟 :param name: 模型名称,数据库中对应的名字 :param modify_pattern_start_time: 模拟开始时间,格式为'2024-11-25T09:00:00+08:00' :param modify_total_duration: 模拟总历时,秒 :param source: 污染源所在的节点ID - :param concentration: 污染源位置处的浓度,单位mg/L,即默认的污染模拟setting为concentration + :param concentration: 污染源位置处的浓度,单位mg/L,即默认的污染模拟setting为concentration(应改为 Set point booster) :param source_pattern: 污染源的时间变化模式,若不传入则默认以恒定浓度持续模拟,时间长度等于duration; 若传入,则格式为{1.0,0.5,1.1}等系数列表pattern_step模拟等于模型的hydraulic time step - :param scheme_Name: 方案名称 + :param scheme_name: 方案名称 :return: """ - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'contaminant_Sim_{name}' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"contaminant_Sim_{name}" if have_project(new_name): if is_project_open(new_name): close_project(new_name) delete_project(new_name) # if is_project_open(name): # close_project(name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) dic_time = get_time(new_name) - dic_time['QUALITY TIMESTEP'] = '0:05:00' + dic_time["QUALITY TIMESTEP"] = "0:05:00" cs = ChangeSet() cs.operations.append(dic_time) set_time(new_name, cs) # set QUALITY TIMESTEP - time_option=get_time(new_name) - hydraulic_step=time_option['HYDRAULIC TIMESTEP'] - secs=from_clock_to_seconds_2(hydraulic_step) - operation_step=0 - #step 1. set duration - if modify_total_duration==None: - modify_total_duration =secs - #step 2. set pattern - if source_pattern!=None: - pt=get_pattern(new_name,source_pattern) - if pt==None: - str_response=str('cant find source_pattern') + time_option = get_time(new_name) + hydraulic_step = time_option["HYDRAULIC TIMESTEP"] + secs = from_clock_to_seconds_2(hydraulic_step) + operation_step = 0 + # step 1. set duration + if modify_total_duration == None: + modify_total_duration = secs + # step 2. set pattern + if source_pattern != None: + pt = get_pattern(new_name, source_pattern) + if pt == None: + str_response = str("cant find source_pattern") return str_response else: - cs_pattern=ChangeSet() - pt={} - factors=[] - tmp_duration= modify_total_duration - while tmp_duration>0: + cs_pattern = ChangeSet() + pt = {} + factors = [] + tmp_duration = modify_total_duration + while tmp_duration > 0: factors.append(1.0) - tmp_duration=tmp_duration-secs - pt['id']='contam_pt' - pt['factors']=factors + tmp_duration = tmp_duration - secs + pt["id"] = "contam_pt" + pt["factors"] = factors cs_pattern.append(pt) - add_pattern(new_name,cs_pattern) - operation_step+=1 - #step 3. set source/initial quality + add_pattern(new_name, cs_pattern) + operation_step += 1 + # step 3. set source/initial quality # source quality - cs_source=ChangeSet() - source_schema={'node':source,'s_type':SOURCE_TYPE_CONCEN,'strength':concentration,'pattern':pt['id']} + cs_source = ChangeSet() + source_schema = { + "node": source, + "s_type": SOURCE_TYPE_CONCEN, + "strength": concentration, + "pattern": pt["id"], + } cs_source.append(source_schema) - source_node=get_source(new_name,source) - if len(source_node)==0: - add_source(new_name,cs_source) + source_node = get_source(new_name, source) + if len(source_node) == 0: + add_source(new_name, cs_source) else: - set_source(new_name,cs_source) + set_source(new_name, cs_source) dict_demand = get_demand(new_name, source) - for demands in dict_demand['demands']: - dict_demand['demands'][dict_demand['demands'].index(demands)]['demand'] = -1 - dict_demand['demands'][dict_demand['demands'].index(demands)]['pattern'] = None + for demands in dict_demand["demands"]: + dict_demand["demands"][dict_demand["demands"].index(demands)]["demand"] = -1 + dict_demand["demands"][dict_demand["demands"].index(demands)]["pattern"] = None cs = ChangeSet() cs.append(dict_demand) set_demand(new_name, cs) # set inflow node @@ -402,20 +547,26 @@ def contaminant_simulation(name: str, modify_pattern_start_time: str, modify_tot # cs = ChangeSet() # cs.append(dict_quality) # set_quality(new_name, cs) - operation_step+=1 - #step 4 set option of quality to chemical - opt=get_option(new_name) - opt['QUALITY']=OPTION_QUALITY_CHEMICAL - cs_option=ChangeSet() + operation_step += 1 + # step 4 set option of quality to chemical + opt = get_option(new_name) + opt["QUALITY"] = OPTION_QUALITY_CHEMICAL + cs_option = ChangeSet() cs_option.append(opt) - set_option(new_name,cs_option) - operation_step+=1 - #step 5. run simulation + set_option(new_name, cs_option) + operation_step += 1 + # step 5. run simulation # result = run_simulation_ex(new_name,'realtime', modify_pattern_start_time, modify_pattern_start_time, modify_total_duration, # downloading_prohibition=True) - simulation.run_simulation(name=new_name, simulation_type='extended', modify_pattern_start_time=modify_pattern_start_time, - modify_total_duration=modify_total_duration, scheme_Type="contaminant_Analysis", scheme_Name=scheme_Name) - + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + scheme_type="contaminant_Analysis", + scheme_name=scheme_name, + ) + # for i in range(1,operation_step): # execute_undo(name) if is_project_open(new_name): @@ -423,12 +574,15 @@ def contaminant_simulation(name: str, modify_pattern_start_time: str, modify_tot delete_project(new_name) # return result + ############################################################ # age analysis 05 ***水龄模拟目前还没和实时模拟打通,不确定是否需要,先不要使用*** ############################################################ -def age_analysis(name: str, modify_pattern_start_time: str, modify_total_duration: int = 900) -> None: +def age_analysis( + name: str, modify_pattern_start_time: str, modify_total_duration: int = 900 +) -> None: """ 水龄模拟 :param name: 模型名称,数据库中对应的名字 @@ -436,24 +590,42 @@ def age_analysis(name: str, modify_pattern_start_time: str, modify_total_duratio :param modify_total_duration: 模拟总历时,秒 :return: """ - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'age_Anal_{name}' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"age_Anal_{name}" if have_project(new_name): if is_project_open(new_name): close_project(new_name) delete_project(new_name) # if is_project_open(name): # close_project(name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) # step 1. run simulation - result = run_simulation_ex(new_name, 'realtime', modify_pattern_start_time, modify_total_duration, - downloading_prohibition=True) + result = run_simulation_ex( + new_name, + "realtime", + modify_pattern_start_time, + modify_total_duration, + downloading_prohibition=True, + ) # step 2. restore the base model status # execute_undo(name) #有疑惑 if is_project_open(new_name): @@ -466,12 +638,12 @@ def age_analysis(name: str, modify_pattern_start_time: str, modify_total_duratio nodes_age = [] node_result = output.node_results() for node in node_result: - nodes_age.append(node['result'][-1]['quality']) + nodes_age.append(node["result"][-1]["quality"]) links_age = [] link_result = output.link_results() for link in link_result: - links_age.append(link['result'][-1]['quality']) - age_result = {'nodes': nodes_age, 'links': links_age} + links_age.append(link["result"][-1]["quality"]) + age_result = {"nodes": nodes_age, "links": links_age} # age_result = {'nodes': nodes_age, 'links': links_age, 'nodeIDs': node_name, 'linkIDs': link_name} return json.dumps(age_result) @@ -481,9 +653,15 @@ def age_analysis(name: str, modify_pattern_start_time: str, modify_total_duratio ############################################################ -def pressure_regulation(name: str, modify_pattern_start_time: str, modify_total_duration: int = 900, - modify_tank_initial_level: dict[str, float] = None, modify_fixed_pump_pattern: dict[str, list] = None, - modify_variable_pump_pattern: dict[str, list] = None, scheme_Name: str = None) -> None: +def pressure_regulation( + name: str, + modify_pattern_start_time: str, + modify_total_duration: int = 900, + modify_tank_initial_level: dict[str, float] = None, + modify_fixed_pump_pattern: dict[str, list] = None, + modify_variable_pump_pattern: dict[str, list] = None, + scheme_name: str = None, +) -> None: """ 区域调压模拟,用来模拟未来15分钟内,开关水泵对区域压力的影响 :param name: 模型名称,数据库中对应的名字 @@ -492,27 +670,40 @@ def pressure_regulation(name: str, modify_pattern_start_time: str, modify_total_ :param modify_tank_initial_level: dict中包含多个水塔,str为水塔的id,float为修改后的initial_level :param modify_fixed_pump_pattern: dict中包含多个水泵模式,str为工频水泵的id,list为修改后的pattern :param modify_variable_pump_pattern: dict中包含多个水泵模式,str为变频水泵的id,list为修改后的pattern - :param scheme_Name: 模拟方案名称 + :param scheme_name: 模拟方案名称 :return: """ - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'pressure_regulation_{name}' + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"pressure_regulation_{name}" if have_project(new_name): if is_project_open(new_name): close_project(new_name) delete_project(new_name) # if is_project_open(name): # close_project(name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) # 全部关泵后,压力计算不合理,改为压力驱动PDA options = get_option(new_name) - options['DEMAND MODEL'] = OPTION_DEMAND_MODEL_PDA - options['REQUIRED PRESSURE'] = '15.0000' + options["DEMAND MODEL"] = OPTION_DEMAND_MODEL_PDA + options["REQUIRED PRESSURE"] = "15.0000" cs_options = ChangeSet() cs_options.append(options) set_option(new_name, cs_options) @@ -523,10 +714,17 @@ def pressure_regulation(name: str, modify_pattern_start_time: str, modify_total_ # pump_control=pump_control, # tank_initial_level_control=tank_initial_level_control, # downloading_prohibition=True) - simulation.run_simulation(name=new_name, simulation_type='extended', modify_pattern_start_time=modify_pattern_start_time, - modify_total_duration=modify_total_duration, modify_tank_initial_level=modify_tank_initial_level, - modify_fixed_pump_pattern=modify_fixed_pump_pattern, modify_variable_pump_pattern=modify_variable_pump_pattern, - scheme_Type="pressure_regulation", scheme_Name=scheme_Name) + simulation.run_simulation( + name=new_name, + simulation_type="extended", + modify_pattern_start_time=modify_pattern_start_time, + modify_total_duration=modify_total_duration, + modify_tank_initial_level=modify_tank_initial_level, + modify_fixed_pump_pattern=modify_fixed_pump_pattern, + modify_variable_pump_pattern=modify_variable_pump_pattern, + scheme_type="pressure_regulation", + scheme_name=scheme_name, + ) if is_project_open(new_name): close_project(new_name) delete_project(new_name) @@ -538,30 +736,50 @@ def pressure_regulation(name: str, modify_pattern_start_time: str, modify_total_ ############################################################ -def project_management(prj_name, start_datetime, pump_control, - tank_initial_level_control=None, region_demand_control=None) -> str: - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'project_management_{prj_name}' +def project_management( + prj_name, + start_datetime, + pump_control, + tank_initial_level_control=None, + region_demand_control=None, +) -> str: + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"project_management_{prj_name}" if have_project(new_name): if is_project_open(new_name): close_project(new_name) delete_project(new_name) # if is_project_open(prj_name): # close_project(prj_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(prj_name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(prj_name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(prj_name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") - result = run_simulation_ex(name=new_name, - simulation_type='realtime', - start_datetime=start_datetime, - duration=86400, - pump_control=pump_control, - tank_initial_level_control=tank_initial_level_control, - region_demand_control=region_demand_control, - downloading_prohibition=True) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) + result = run_simulation_ex( + name=new_name, + simulation_type="realtime", + start_datetime=start_datetime, + duration=86400, + pump_control=pump_control, + tank_initial_level_control=tank_initial_level_control, + region_demand_control=region_demand_control, + downloading_prohibition=True, + ) if is_project_open(new_name): close_project(new_name) delete_project(new_name) @@ -573,9 +791,14 @@ def project_management(prj_name, start_datetime, pump_control, ############################################################ -def scheduling_simulation(prj_name, start_time, pump_control, tank_id, water_plant_output_id, time_delta=300) -> str: - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'scheduling_{prj_name}' +def scheduling_simulation( + prj_name, start_time, pump_control, tank_id, water_plant_output_id, time_delta=300 +) -> str: + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"scheduling_{prj_name}" if have_project(new_name): if is_project_open(new_name): @@ -583,52 +806,73 @@ def scheduling_simulation(prj_name, start_time, pump_control, tank_id, water_pla delete_project(new_name) # if is_project_open(prj_name): # close_project(prj_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(prj_name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(prj_name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(prj_name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) - run_simulation_ex(new_name, 'realtime', start_time, duration=0, pump_control=pump_control) + run_simulation_ex( + new_name, "realtime", start_time, duration=0, pump_control=pump_control + ) if not is_project_open(new_name): open_project(new_name) tank = get_tank(new_name, tank_id) # 水塔信息 - tank_floor_space = pi * pow(tank['diameter'] / 2, 2) # 水塔底面积(m^2) - tank_init_level = tank['init_level'] # 水塔初始水位(m) - tank_pipes_id = tank['links'] # pipes list + tank_floor_space = pi * pow(tank["diameter"] / 2, 2) # 水塔底面积(m^2) + tank_init_level = tank["init_level"] # 水塔初始水位(m) + tank_pipes_id = tank["links"] # pipes list - tank_pipe_flow_direction = {} # 管道流向修正系数, 水塔为下游节点时为1, 水塔为上游节点时为-1 + tank_pipe_flow_direction = ( + {} + ) # 管道流向修正系数, 水塔为下游节点时为1, 水塔为上游节点时为-1 for pipe_id in tank_pipes_id: - if get_pipe(new_name, pipe_id)['node2'] == tank_id: # 水塔为下游节点 + if get_pipe(new_name, pipe_id)["node2"] == tank_id: # 水塔为下游节点 tank_pipe_flow_direction[pipe_id] = 1 else: tank_pipe_flow_direction[pipe_id] = -1 output = Output("./temp/{}.db.out".format(new_name)) - node_results = output.node_results() # [{'node': str, 'result': [{'pressure': float}]}] + node_results = ( + output.node_results() + ) # [{'node': str, 'result': [{'pressure': float}]}] water_plant_output_pressure = 0 for node_result in node_results: - if node_result['node'] == water_plant_output_id: # 水厂出水压力(m) - water_plant_output_pressure = node_result['result'][-1]['pressure'] + if node_result["node"] == water_plant_output_id: # 水厂出水压力(m) + water_plant_output_pressure = node_result["result"][-1]["pressure"] water_plant_output_pressure /= 100 # 预计水厂出水压力(Mpa) pipe_results = output.link_results() # [{'link': str, 'result': [{'flow': float}]}] tank_inflow = 0 for pipe_result in pipe_results: for pipe_id in tank_pipes_id: # 遍历与水塔相连的管道 - if pipe_result['link'] == pipe_id: # 水塔入流流量(L/s) - tank_inflow += pipe_result['result'][-1]['flow'] * tank_pipe_flow_direction[pipe_id] - tank_inflow /= 1000 # 水塔入流流量(m^3/s) + if pipe_result["link"] == pipe_id: # 水塔入流流量(L/s) + tank_inflow += ( + pipe_result["result"][-1]["flow"] + * tank_pipe_flow_direction[pipe_id] + ) + tank_inflow /= 1000 # 水塔入流流量(m^3/s) tank_level_delta = tank_inflow * time_delta / tank_floor_space # 水塔水位改变值(m) tank_level = tank_init_level + tank_level_delta # 预计水塔水位(m) - simulation_results = {'water_plant_output_pressure': water_plant_output_pressure, - 'tank_init_level': tank_init_level, - 'tank_level': tank_level} + simulation_results = { + "water_plant_output_pressure": water_plant_output_pressure, + "tank_init_level": tank_init_level, + "tank_level": tank_level, + } if is_project_open(new_name): close_project(new_name) @@ -637,10 +881,14 @@ def scheduling_simulation(prj_name, start_time, pump_control, tank_id, water_pla return json.dumps(simulation_results) -def daily_scheduling_simulation(prj_name, start_time, pump_control, - reservoir_id, tank_id, water_plant_output_id) -> str: - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Analysis.") - new_name = f'daily_scheduling_{prj_name}' +def daily_scheduling_simulation( + prj_name, start_time, pump_control, reservoir_id, tank_id, water_plant_output_id +) -> str: + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Analysis." + ) + new_name = f"daily_scheduling_{prj_name}" if have_project(new_name): if is_project_open(new_name): @@ -648,38 +896,56 @@ def daily_scheduling_simulation(prj_name, start_time, pump_control, delete_project(new_name) # if is_project_open(prj_name): # close_project(prj_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Copying Database.") - CopyProjectEx()(prj_name, new_name, - ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Start Opening Database.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Copying Database." + ) + # CopyProjectEx()(prj_name, new_name, + # ['operation', 'current_operation', 'restore_operation', 'batch_operation', 'operation_table']) + copy_project(prj_name + "_template", new_name) + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Start Opening Database." + ) open_project(new_name) - print(datetime.now(pytz.timezone('Asia/Shanghai')).strftime("%Y-%m-%d %H:%M:%S") + " -- Database Loading OK.") + print( + datetime.now(pytz.timezone("Asia/Shanghai")).strftime("%Y-%m-%d %H:%M:%S") + + " -- Database Loading OK." + ) - run_simulation_ex(new_name, 'realtime', start_time, duration=86400, pump_control=pump_control) + run_simulation_ex( + new_name, "realtime", start_time, duration=86400, pump_control=pump_control + ) if not is_project_open(new_name): open_project(new_name) output = Output("./temp/{}.db.out".format(new_name)) - node_results = output.node_results() # [{'node': str, 'result': [{'pressure': float, 'head': float}]}] + node_results = ( + output.node_results() + ) # [{'node': str, 'result': [{'pressure': float, 'head': float}]}] water_plant_output_pressure = [] reservoir_level = [] tank_level = [] for node_result in node_results: - if node_result['node'] == water_plant_output_id: - for result in node_result['result']: - water_plant_output_pressure.append(result['pressure'] / 100) # 水厂出水压力(Mpa) - elif node_result['node'] == reservoir_id: - for result in node_result['result']: - reservoir_level.append(result['head'] - 250.35) # 清水池液位(m) - elif node_result['node'] == tank_id: - for result in node_result['result']: - tank_level.append(result['pressure']) # 调节池液位(m) + if node_result["node"] == water_plant_output_id: + for result in node_result["result"]: + water_plant_output_pressure.append( + result["pressure"] / 100 + ) # 水厂出水压力(Mpa) + elif node_result["node"] == reservoir_id: + for result in node_result["result"]: + reservoir_level.append(result["head"] - 250.35) # 清水池液位(m) + elif node_result["node"] == tank_id: + for result in node_result["result"]: + tank_level.append(result["pressure"]) # 调节池液位(m) - simulation_results = {'water_plant_output_pressure': water_plant_output_pressure, - 'reservoir_level': reservoir_level, - 'tank_level': tank_level} + simulation_results = { + "water_plant_output_pressure": water_plant_output_pressure, + "reservoir_level": reservoir_level, + "tank_level": tank_level, + } if is_project_open(new_name): close_project(new_name) @@ -687,19 +953,21 @@ def daily_scheduling_simulation(prj_name, start_time, pump_control, return json.dumps(simulation_results) + ############################################################ # network_update 10 ############################################################ + def network_update(file_path: str) -> None: """ 更新pg数据库中的inp文件 :param file_path: inp文件 :return: """ - read_inp('szh', file_path) + read_inp("szh", file_path) - csv_path = './history_pattern_flow.csv' + csv_path = "./history_pattern_flow.csv" # # 检查文件是否存在 # if os.path.exists(csv_path): @@ -730,16 +998,18 @@ def network_update(file_path: str) -> None: # 连接到 PostgreSQL 数据库(这里是数据库 "bb") with psycopg.connect(f"dbname={project_info.name} host=127.0.0.1") as conn: with conn.cursor() as cur: - with open(csv_path, newline='', encoding='utf-8-sig') as csvfile: + with open(csv_path, newline="", encoding="utf-8-sig") as csvfile: reader = csv.DictReader(csvfile) for row in reader: # 直接将数据插入,不进行唯一性检查 - insert_sql = sql.SQL(""" + insert_sql = sql.SQL( + """ INSERT INTO history_patterns_flows (id, factor, flow) VALUES (%s, %s, %s); - """) + """ + ) # 将数据插入数据库 - cur.execute(insert_sql, (row['id'], row['factor'], row['flow'])) + cur.execute(insert_sql, (row["id"], row["factor"], row["flow"])) conn.commit() print("数据成功导入到 'history_patterns_flows' 表格。") else: @@ -753,16 +1023,16 @@ def submit_scada_info(name: str, coord_id: str) -> None: :param coord_id: 坐标系的id,如4326,根据原始坐标信息输入 :return: """ - scada_info_path = './scada_info.csv' + scada_info_path = "./scada_info.csv" # 检查文件是否存在 if os.path.exists(scada_info_path): print(f"scada_info文件存在,开始处理...") # 自动检测文件编码 - with open(scada_info_path, 'rb') as file: + with open(scada_info_path, "rb") as file: raw_data = file.read() detected = chardet.detect(raw_data) - file_encoding = detected['encoding'] + file_encoding = detected["encoding"] print(f"检测到的文件编码:{file_encoding}") try: # 动态替换数据库名称 @@ -780,27 +1050,51 @@ def submit_scada_info(name: str, coord_id: str) -> None: cur.execute("DELETE FROM scada_info;") print("表记录已清空。") - with open(scada_info_path, newline='', encoding=file_encoding) as csvfile: + with open( + scada_info_path, newline="", encoding=file_encoding + ) as csvfile: reader = csv.DictReader(csvfile) for row in reader: # 将CSV单元格值为空的字段转换为 None - cleaned_row = {key: (value if value.strip() else None) for key, value in row.items()} + cleaned_row = { + key: (value if value.strip() else None) + for key, value in row.items() + } # 处理 associated_source_outflow_id 列动态变化 - associated_columns = [f"associated_source_outflow_id{i}" for i in range(1, 21)] + associated_columns = [ + f"associated_source_outflow_id{i}" for i in range(1, 21) + ] associated_values = [ - (cleaned_row.get(col).strip() if cleaned_row.get(col) and cleaned_row.get( - col).strip() else None) + ( + cleaned_row.get(col).strip() + if cleaned_row.get(col) + and cleaned_row.get(col).strip() + else None + ) for col in associated_columns ] # 将 X_coor 和 Y_coor 转换为 geometry 类型 - x_coor = float(cleaned_row['X_coor']) if cleaned_row['X_coor'] else None - y_coor = float(cleaned_row['Y_coor']) if cleaned_row['Y_coor'] else None - coord = f"SRID={coord_id};POINT({x_coor} {y_coor})" if x_coor and y_coor else None + x_coor = ( + float(cleaned_row["X_coor"]) + if cleaned_row["X_coor"] + else None + ) + y_coor = ( + float(cleaned_row["Y_coor"]) + if cleaned_row["Y_coor"] + else None + ) + coord = ( + f"SRID={coord_id};POINT({x_coor} {y_coor})" + if x_coor and y_coor + else None + ) # 准备插入 SQL 语句 - insert_sql = sql.SQL(""" + insert_sql = sql.SQL( + """ INSERT INTO scada_info ( id, type, associated_element_id, associated_pattern, associated_pipe_flow_id, {associated_columns}, @@ -811,18 +1105,34 @@ def submit_scada_info(name: str, coord_id: str) -> None: %s, %s, %s, %s, %s, {associated_placeholders}, %s, %s, %s, %s, %s, %s, %s ); - """).format( - associated_columns=sql.SQL(", ").join(sql.Identifier(col) for col in associated_columns), - associated_placeholders=sql.SQL(", ").join(sql.Placeholder() for _ in associated_columns) + """ + ).format( + associated_columns=sql.SQL(", ").join( + sql.Identifier(col) for col in associated_columns + ), + associated_placeholders=sql.SQL(", ").join( + sql.Placeholder() for _ in associated_columns + ), ) # 将数据插入数据库 - cur.execute(insert_sql, ( - cleaned_row['id'], cleaned_row['type'], cleaned_row['associated_element_id'], - cleaned_row.get('associated_pattern'), cleaned_row.get('associated_pipe_flow_id'), - *associated_values, cleaned_row.get('API_query_id'), - cleaned_row['transmission_mode'], cleaned_row['transmission_frequency'], - cleaned_row['reliability'], x_coor, y_coor, coord - )) + cur.execute( + insert_sql, + ( + cleaned_row["id"], + cleaned_row["type"], + cleaned_row["associated_element_id"], + cleaned_row.get("associated_pattern"), + cleaned_row.get("associated_pipe_flow_id"), + *associated_values, + cleaned_row.get("API_query_id"), + cleaned_row["transmission_mode"], + cleaned_row["transmission_frequency"], + cleaned_row["reliability"], + x_coor, + y_coor, + coord, + ), + ) conn.commit() print("数据成功导入到 'scada_info' 表格。") except Exception as e: @@ -848,7 +1158,7 @@ def create_user(name: str, username: str, password: str): with conn.cursor() as cur: cur.execute( "INSERT INTO users (username, password) VALUES (%s, %s)", - (username, password) + (username, password), ) # 提交事务 conn.commit() @@ -890,7 +1200,10 @@ def scheme_name_exists(name: str, scheme_name: str) -> bool: conn_string = get_pgconn_string(db_name=name) with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: - cur.execute("SELECT COUNT(*) FROM scheme_list WHERE scheme_name = %s", (scheme_name,)) + cur.execute( + "SELECT COUNT(*) FROM scheme_list WHERE scheme_name = %s", + (scheme_name,), + ) result = cur.fetchone() if result is not None and result[0] > 0: return True @@ -902,7 +1215,14 @@ def scheme_name_exists(name: str, scheme_name: str) -> bool: # 2025/03/23 -def store_scheme_info(name: str, scheme_name: str, scheme_type: str, username: str, scheme_start_time: str, scheme_detail: dict): +def store_scheme_info( + name: str, + scheme_name: str, + scheme_type: str, + username: str, + scheme_start_time: str, + scheme_detail: dict, +): """ 将一条方案记录插入 scheme_list 表中 :param name: 数据库名称 @@ -923,7 +1243,16 @@ def store_scheme_info(name: str, scheme_name: str, scheme_type: str, username: s """ # 将字典转换为 JSON 字符串 scheme_detail_json = json.dumps(scheme_detail) - cur.execute(sql, (scheme_name, scheme_type, username, scheme_start_time, scheme_detail_json)) + cur.execute( + sql, + ( + scheme_name, + scheme_type, + username, + scheme_start_time, + scheme_detail_json, + ), + ) conn.commit() print("方案信息存储成功!") except Exception as e: @@ -942,7 +1271,9 @@ def delete_scheme_info(name: str, scheme_name: str) -> None: with psycopg.connect(conn_string) as conn: with conn.cursor() as cur: # 使用参数化查询删除方案记录 - cur.execute("DELETE FROM scheme_list WHERE scheme_name = %s", (scheme_name,)) + cur.execute( + "DELETE FROM scheme_list WHERE scheme_name = %s", (scheme_name,) + ) conn.commit() print(f"方案 {scheme_name} 删除成功!") except Exception as e: @@ -989,15 +1320,19 @@ def upload_shp_to_pg(name: str, table_name: str, role: str, shp_file_path: str): gdf = gpd.read_file(shp_file_path) # 检查投影坐标系(CRS),并确保是 EPSG:4326 - if gdf.crs.to_string() != 'EPSG:4490': + if gdf.crs.to_string() != "EPSG:4490": gdf = gdf.to_crs(epsg=4490) # 使用 GeoDataFrame 的 .to_postgis 方法将数据写入 PostgreSQL # 需要在数据库中提前安装 PostGIS 扩展 engine = create_engine(f"postgresql+psycopg2://{role}:@127.0.0.1/{name}") - gdf.to_postgis(table_name, engine, if_exists='replace', index=True, index_label='id') + gdf.to_postgis( + table_name, engine, if_exists="replace", index=True, index_label="id" + ) - print(f"Shapefile 文件成功上传到 PostgreSQL 数据库 '{name}' 的表 '{table_name}'.") + print( + f"Shapefile 文件成功上传到 PostgreSQL 数据库 '{name}' 的表 '{table_name}'." + ) except Exception as e: print(f"上传 Shapefile 到 PostgreSQL 时出错:{e}") @@ -1034,9 +1369,9 @@ def submit_risk_probability_result(name: str, result_file_path: str) -> None: print("表记录已清空。") # 读取Excel并转换x/y列为列表 - df = pd.read_excel(result_file_path, sheet_name='Sheet1') - df['x'] = df['x'].apply(ast.literal_eval) - df['y'] = df['y'].apply(ast.literal_eval) + df = pd.read_excel(result_file_path, sheet_name="Sheet1") + df["x"] = df["x"].apply(ast.literal_eval) + df["y"] = df["y"].apply(ast.literal_eval) # 批量插入数据 for index, row in df.iterrows(): @@ -1045,13 +1380,16 @@ def submit_risk_probability_result(name: str, result_file_path: str) -> None: (pipeID, pipeage, risk_probability_now, x, y) VALUES (%s, %s, %s, %s, %s) """ - cur.execute(insert_query, ( - row['pipeID'], - row['pipeage'], - row['risk_probability_now'], - row['x'], # 直接传递列表 - row['y'] # 同上 - )) + cur.execute( + insert_query, + ( + row["pipeID"], + row["pipeage"], + row["risk_probability_now"], + row["x"], # 直接传递列表 + row["y"], # 同上 + ), + ) conn.commit() print("风险评估结果导入成功") @@ -1060,8 +1398,9 @@ def submit_risk_probability_result(name: str, result_file_path: str) -> None: print(f"导入时出错:{e}") -def pressure_sensor_placement_sensitivity(name: str, scheme_name: str, sensor_number: int, - min_diameter: int, username: str) -> None: +def pressure_sensor_placement_sensitivity( + name: str, scheme_name: str, sensor_number: int, min_diameter: int, username: str +) -> None: """ 基于改进灵敏度法进行压力监测点优化布置 :param name: 数据库名称 @@ -1071,7 +1410,9 @@ def pressure_sensor_placement_sensitivity(name: str, scheme_name: str, sensor_nu :param username: 用户名 :return: """ - sensor_location = sensitivity.get_ID(name=name, sensor_num=sensor_number, min_diameter=min_diameter) + sensor_location = sensitivity.get_ID( + name=name, sensor_num=sensor_number, min_diameter=min_diameter + ) try: conn_string = get_pgconn_string(db_name=name) with psycopg.connect(conn_string) as conn: @@ -1081,16 +1422,27 @@ def pressure_sensor_placement_sensitivity(name: str, scheme_name: str, sensor_nu VALUES (%s, %s, %s, %s, %s) """ - cur.execute(sql, (scheme_name, sensor_number, min_diameter, username, sensor_location)) + cur.execute( + sql, + ( + scheme_name, + sensor_number, + min_diameter, + username, + sensor_location, + ), + ) conn.commit() print("方案信息存储成功!") except Exception as e: print(f"存储方案信息时出错:{e}") -#2025/08/21 + +# 2025/08/21 # 基于kmeans聚类法进行压力监测点优化布置 -def pressure_sensor_placement_kmeans(name: str, scheme_name: str, sensor_number: int, - min_diameter: int, username: str) -> None: +def pressure_sensor_placement_kmeans( + name: str, scheme_name: str, sensor_number: int, min_diameter: int, username: str +) -> None: """ 基于聚类法进行压力监测点优化布置 :param name: 数据库名称(注意,此处数据库名称也是inp文件名称,inp文件与pg库名要一样) @@ -1100,10 +1452,12 @@ def pressure_sensor_placement_kmeans(name: str, scheme_name: str, sensor_number: :param username: 用户名 :return: """ - #dump_inp - inp_name = f'./db_inp/{name}.db.inp' - dump_inp(name,inp_name,'2') - sensor_location = api_ex.kmeans_sensor.kmeans_sensor_placement(name=name, sensor_num=sensor_number, min_diameter=min_diameter) + # dump_inp + inp_name = f"./db_inp/{name}.db.inp" + dump_inp(name, inp_name, "2") + sensor_location = kmeans_sensor.kmeans_sensor_placement( + name=name, sensor_num=sensor_number, min_diameter=min_diameter + ) try: conn_string = get_pgconn_string(db_name=name) with psycopg.connect(conn_string) as conn: @@ -1113,78 +1467,90 @@ def pressure_sensor_placement_kmeans(name: str, scheme_name: str, sensor_number: VALUES (%s, %s, %s, %s, %s) """ - cur.execute(sql, (scheme_name, sensor_number, min_diameter, username, sensor_location)) + cur.execute( + sql, + ( + scheme_name, + sensor_number, + min_diameter, + username, + sensor_location, + ), + ) conn.commit() print("方案信息存储成功!") except Exception as e: print(f"存储方案信息时出错:{e}") + ############################################################ # 流量监测数据清洗 ***卡尔曼滤波法*** ############################################################ -#2025/08/21 hxyan +# 2025/08/21 hxyan + def flow_data_clean(input_csv_file: str) -> str: """ 读取 input_csv_path 中的每列时间序列,使用一维 Kalman 滤波平滑并用预测值替换基于 3σ 检测出的异常点。 保存输出为:_cleaned.xlsx(与输入同目录),并返回输出文件的绝对路径。如有同名文件存在,则覆盖。 - :param: input_csv_file: 输入的 CSV 文件明或路径 + :param: input_csv_file: 输入的 CSV 文件明或路径 :return: 输出文件的绝对路径 """ - # 提供的 input_csv_path 绝对路径,以下为 默认脚本目录下同名 CSV 文件,构建绝对路径,可根据情况修改 script_dir = os.path.dirname(os.path.abspath(__file__)) - input_csv_path= os.path.join(script_dir, input_csv_file) + input_csv_path = os.path.join(script_dir, input_csv_file) # 检查文件是否存在 if not os.path.exists(input_csv_path): raise FileNotFoundError(f"指定的文件不存在: {input_csv_path}") # 调用 Fdataclean.clean_flow_data_kf 函数进行数据清洗 - out_xlsx_path = api_ex.Fdataclean.clean_flow_data_kf(input_csv_path) - print("清洗后的数据已保存到:", out_xlsx_path ) + out_xlsx_path = flow_data_clean.clean_flow_data_kf(input_csv_path) + print("清洗后的数据已保存到:", out_xlsx_path) ############################################################ # 压力监测数据清洗 ***kmean++法*** ############################################################ -#2025/08/21 hxyan +# 2025/08/21 hxyan + def pressure_data_clean(input_csv_file: str) -> str: """ 读取 input_csv_path 中的每列时间序列,使用Kmean++清洗数据。 保存输出为:_cleaned.xlsx(与输入同目录),并返回输出文件的绝对路径。如有同名文件存在,则覆盖。 原始数据在 sheet 'raw_pressure_data',处理后数据在 sheet 'cleaned_pressusre_data'。 - :param input_csv_path: 输入的 CSV 文件路径 + :param input_csv_path: 输入的 CSV 文件路径 :return: 输出文件的绝对路径 """ # 提供的 input_csv_path 绝对路径,以下为 默认脚本目录下同名 CSV 文件,构建绝对路径,可根据情况修改 script_dir = os.path.dirname(os.path.abspath(__file__)) - input_csv_path= os.path.join(script_dir, input_csv_file) + input_csv_path = os.path.join(script_dir, input_csv_file) # 检查文件是否存在 if not os.path.exists(input_csv_path): raise FileNotFoundError(f"指定的文件不存在: {input_csv_path}") # 调用 Fdataclean.clean_flow_data_kf 函数进行数据清洗 - out_xlsx_path = api_ex.Pdataclean.clean_pressure_data_km(input_csv_path) - print("清洗后的数据已保存到:", out_xlsx_path ) + out_xlsx_path = pressure_data_clean.clean_pressure_data_km(input_csv_path) + print("清洗后的数据已保存到:", out_xlsx_path) -if __name__ == '__main__': - # contaminant_simulation('bb_model','2024-06-24T00:00:00Z','ZBBDTZDP009034',30,1800) - # flushing_analysis('bb_model','2024-04-01T08:00:00Z',{'GSD230719205857733F8F5214FF','GSD230719205857C0AF65B6A170'},'GSD2307192058570DEDF28E4F73',0,duration=900) - # flushing_analysis('bb_model', '2024-08-26T08:00:00Z', ['GSD2307192058572E5C0E14D83E'], [0.5], 'ZBBDTZDP009410', 0, - # duration=1800) - # valve_close_analysis('bb_model','2024-04-01T08:00:00Z',['GSD2307192058576122D929EE99(L)'],duration=1800) - # burst_analysis('bb','2024-04-01T08:00:00Z','ZBBGXSZW000001',burst_size=200,duration=1800) - #run_simulation('beibeizone','2024-04-01T08:00:00Z') -# str_dump=dump_output('h:\\OneDrive\\tjwaterserver\\temp\\beibeizone.db_no_burst.out') -# with open("out_dump.txt", "w") as f: -# f.write(str_dump) -# str_dump=dump_output('h:\\OneDrive\\tjwaterserver\\temp\\beibeizone.db_busrtID(ZBBGXSZW000001).out') -# with open("burst_out_dump.txt", "w") as f: -# f.write(str_dump) +if __name__ == "__main__": + # contaminant_simulation('bb_model','2024-06-24T00:00:00Z','ZBBDTZDP009034',30,1800) + # flushing_analysis('bb_model','2024-04-01T08:00:00Z',{'GSD230719205857733F8F5214FF','GSD230719205857C0AF65B6A170'},'GSD2307192058570DEDF28E4F73',0,duration=900) + # flushing_analysis('bb_model', '2024-08-26T08:00:00Z', ['GSD2307192058572E5C0E14D83E'], [0.5], 'ZBBDTZDP009410', 0, + # duration=1800) + # valve_close_analysis('bb_model','2024-04-01T08:00:00Z',['GSD2307192058576122D929EE99(L)'],duration=1800) + + # burst_analysis('bb','2024-04-01T08:00:00Z','ZBBGXSZW000001',burst_size=200,duration=1800) + # run_simulation('beibeizone','2024-04-01T08:00:00Z') + # str_dump=dump_output('h:\\OneDrive\\tjwaterserver\\temp\\beibeizone.db_no_burst.out') + # with open("out_dump.txt", "w") as f: + # f.write(str_dump) + # str_dump=dump_output('h:\\OneDrive\\tjwaterserver\\temp\\beibeizone.db_busrtID(ZBBGXSZW000001).out') + # with open("burst_out_dump.txt", "w") as f: + # f.write(str_dump) # # 更新inp文件,并插入history_patterns_flows # network_update('fx0217-mass injection.inp') @@ -1200,7 +1566,7 @@ if __name__ == '__main__': # 示例1:burst_analysis # burst_analysis(name='bb', modify_pattern_start_time='2025-04-17T00:00:00+08:00', - # burst_ID='GSD230112144241FA18292A84CB', burst_size=400, modify_total_duration=1800, scheme_Name='GSD230112144241FA18292A84CB_400') + # burst_ID='GSD230112144241FA18292A84CB', burst_size=400, modify_total_duration=1800, scheme_name='GSD230112144241FA18292A84CB_400') # 示例:create_user # create_user(name=project_info.name, username='tjwater dev', password='123456') @@ -1229,4 +1595,4 @@ if __name__ == '__main__': # pressure_sensor_placement_kmeans(name=project_info.name, scheme_name='sensor_1103', sensor_number=35, min_diameter=300, username='admin') # 测试:convert emitters coefficients - convert_to_local_unit("szh",100) \ No newline at end of file + convert_to_local_unit("szh", 100) diff --git a/open_szh.py b/scripts/open_szh.py similarity index 64% rename from open_szh.py rename to scripts/open_szh.py index 6858b40..b2c20ca 100644 --- a/open_szh.py +++ b/scripts/open_szh.py @@ -1,5 +1,5 @@ import sys -from tjnetwork import * +from app.services.tjnetwork import open_project def main(): open_project('szh') diff --git a/redis_clear_all_keys.py b/scripts/redis_clear_all_keys.py similarity index 100% rename from redis_clear_all_keys.py rename to scripts/redis_clear_all_keys.py diff --git a/restartpg.bat b/scripts/restartpg.bat similarity index 100% rename from restartpg.bat rename to scripts/restartpg.bat diff --git a/restore_project.py b/scripts/restore_project.py similarity index 75% rename from restore_project.py rename to scripts/restore_project.py index d7cbcef..8655496 100644 --- a/restore_project.py +++ b/scripts/restore_project.py @@ -1,5 +1,5 @@ import sys -from tjnetwork import * +from app.services.tjnetwork import close_project, open_project, restore def main(): if len(sys.argv) != 2: diff --git a/restore_projects.py b/scripts/restore_projects.py similarity index 67% rename from restore_projects.py rename to scripts/restore_projects.py index d984968..8ad5b6a 100644 --- a/restore_projects.py +++ b/scripts/restore_projects.py @@ -1,4 +1,4 @@ -from tjnetwork import * +from app.services.tjnetwork import close_project, list_project, open_project, restore def main(): for p in list_project(): diff --git a/scripts/run_server.py b/scripts/run_server.py new file mode 100644 index 0000000..70416aa --- /dev/null +++ b/scripts/run_server.py @@ -0,0 +1,21 @@ +import asyncio +import sys +import os +import uvicorn + +# 将项目根目录添加到 python 路径 +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +if __name__ == "__main__": + # Windows 设置事件循环策略 + if sys.platform == "win32": + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + + # 用 uvicorn.run 支持 workers 参数 + uvicorn.run( + "app.main:app", + host="0.0.0.0", + port=8000, + # workers=4, # 这里可以设置多进程 + loop="asyncio", + ) diff --git a/run_simlation.py b/scripts/run_simlation.py similarity index 74% rename from run_simlation.py rename to scripts/run_simlation.py index 2d7408b..d97bf66 100644 --- a/run_simlation.py +++ b/scripts/run_simlation.py @@ -1,4 +1,4 @@ -from tjnetwork import * +from app.services.tjnetwork import open_project from get_current_status import * def run_simulation(cur_datetime:str=None)->str: diff --git a/scripts/setup_security.sh b/scripts/setup_security.sh new file mode 100755 index 0000000..003f5c8 --- /dev/null +++ b/scripts/setup_security.sh @@ -0,0 +1,122 @@ +#!/bin/bash + +# TJWater Server 安全功能快速设置脚本 + +set -e + +echo "==================================" +echo "TJWater Server 安全功能设置" +echo "==================================" +echo "" + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# 步骤 1: 检查依赖 +echo "📦 步骤 1/5: 检查 Python 依赖..." +if ! python -c "import cryptography, passlib, jose" 2>/dev/null; then + echo -e "${YELLOW}缺少依赖,正在安装...${NC}" + pip install cryptography passlib python-jose bcrypt +else + echo -e "${GREEN}✓ 依赖已安装${NC}" +fi +echo "" + +# 步骤 2: 生成密钥 +echo "🔑 步骤 2/5: 生成安全密钥..." + +if [ ! -f .env ]; then + echo "正在创建 .env 文件..." + cp .env.example .env + + # 生成 JWT 密钥 + JWT_KEY=$(openssl rand -hex 32) + sed -i "s/SECRET_KEY=.*/SECRET_KEY=$JWT_KEY/" .env + echo -e "${GREEN}✓ JWT 密钥已生成${NC}" + + # 生成加密密钥 + ENC_KEY=$(python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())") + sed -i "s/ENCRYPTION_KEY=.*/ENCRYPTION_KEY=$ENC_KEY/" .env + echo -e "${GREEN}✓ 加密密钥已生成${NC}" +else + echo -e "${YELLOW}⚠ .env 文件已存在,跳过生成${NC}" +fi +echo "" + +# 步骤 3: 数据库配置 +echo "💾 步骤 3/5: 数据库配置..." +read -p "请输入数据库名称 [默认: tjwater]: " DB_NAME +DB_NAME=${DB_NAME:-tjwater} + +read -p "请输入数据库用户 [默认: postgres]: " DB_USER +DB_USER=${DB_USER:-postgres} + +read -sp "请输入数据库密码: " DB_PASS +echo "" + +# 更新 .env +sed -i "s/DB_NAME=.*/DB_NAME=$DB_NAME/" .env +sed -i "s/DB_USER=.*/DB_USER=$DB_USER/" .env +sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=$DB_PASS/" .env + +echo -e "${GREEN}✓ 数据库配置已更新${NC}" +echo "" + +# 步骤 4: 执行数据库迁移 +echo "🗄️ 步骤 4/5: 执行数据库迁移..." +read -p "是否立即执行数据库迁移?(y/n) [y]: " DO_MIGRATION +DO_MIGRATION=${DO_MIGRATION:-y} + +if [ "$DO_MIGRATION" = "y" ]; then + echo "正在执行迁移脚本..." + + PGPASSWORD=$DB_PASS psql -U $DB_USER -d $DB_NAME -f resources/sql/001_create_users_table.sql 2>&1 | grep -v "NOTICE" + if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ 用户表创建成功${NC}" + else + echo -e "${RED}✗ 用户表创建失败${NC}" + fi + + PGPASSWORD=$DB_PASS psql -U $DB_USER -d $DB_NAME -f resources/sql/002_create_audit_logs_table.sql 2>&1 | grep -v "NOTICE" + if [ $? -eq 0 ]; then + echo -e "${GREEN}✓ 审计日志表创建成功${NC}" + else + echo -e "${RED}✗ 审计日志表创建失败${NC}" + fi +else + echo -e "${YELLOW}⚠ 跳过数据库迁移,请稍后手动执行:${NC}" + echo " psql -U $DB_USER -d $DB_NAME -f resources/sql/001_create_users_table.sql" + echo " psql -U $DB_USER -d $DB_NAME -f resources/sql/002_create_audit_logs_table.sql" +fi +echo "" + +# 步骤 5: 测试 +echo "🧪 步骤 5/5: 运行测试..." +if python tests/test_encryption.py 2>&1; then + echo -e "${GREEN}✓ 加密功能测试通过${NC}" +else + echo -e "${RED}✗ 加密功能测试失败${NC}" +fi +echo "" + +# 完成 +echo "==================================" +echo -e "${GREEN}✅ 设置完成!${NC}" +echo "==================================" +echo "" +echo "默认管理员账号:" +echo " 用户名: admin" +echo " 密码: admin123" +echo "" +echo " 用户名: tjwater" +echo " 密码: tjwater@123" +echo "" +echo "下一步:" +echo " 1. 查看文档: cat SECURITY_README.md" +echo " 2. 查看部署指南: cat DEPLOYMENT.md" +echo " 3. 启动服务器: uvicorn app.main:app --reload" +echo " 4. 访问文档: http://localhost:8000/docs" +echo "" diff --git a/startfastapiserver.bat b/scripts/startfastapiserver.bat similarity index 100% rename from startfastapiserver.bat rename to scripts/startfastapiserver.bat diff --git a/startpg.bat b/scripts/startpg.bat similarity index 100% rename from startpg.bat rename to scripts/startpg.bat diff --git a/test_tjnetwork.py b/scripts/test_tjnetwork.py similarity index 97% rename from test_tjnetwork.py rename to scripts/test_tjnetwork.py index 03055e4..908ec13 100644 --- a/test_tjnetwork.py +++ b/scripts/test_tjnetwork.py @@ -1,6 +1,254 @@ import pytest import random -from tjnetwork import * +from app.services.tjnetwork import ( + API_ADD, + API_DELETE, + API_UPDATE, + CURVE, + CURVE_TYPE_EFFICIENCY, + CURVE_TYPE_PUMP, + ChangeSet, + JUNCTION, + LINK_STATUS_OPEN, + MIXING_MODEL_2COMP, + MIXING_MODEL_MIXED, + OPTION_DEMAND_MODEL_DDA, + OPTION_DEMAND_MODEL_PDA, + OPTION_HEADLOSS_DW, + OPTION_HEADLOSS_HW, + OPTION_PRESSURE_KPA, + OPTION_PRESSURE_METERS, + OPTION_PRESSURE_PSI, + OPTION_QUALITY_NONE, + OPTION_QUALITY_TRACE, + OPTION_UNBALANCED_CONTINUE, + OPTION_UNBALANCED_STOP, + OPTION_UNITS_GPM, + OPTION_UNITS_LPS, + OPTION_V3_DEMAND_MODEL_CONSTRAINED, + OPTION_V3_DEMAND_MODEL_FIXED, + OPTION_V3_DEMAND_MODEL_LOGISTIC, + OPTION_V3_DEMAND_MODEL_POWER, + OPTION_V3_FLOW_UNITS_GPM, + OPTION_V3_FLOW_UNITS_LPS, + OPTION_V3_HEADLOSS_MODEL_DW, + OPTION_V3_HEADLOSS_MODEL_HW, + OPTION_V3_IF_UNBALANCED_CONTINUE, + OPTION_V3_IF_UNBALANCED_STOP, + OPTION_V3_LEAKAGE_MODEL_NONE, + OPTION_V3_LEAKAGE_MODEL_POWER, + OPTION_V3_PRESSURE_UNITS_KPA, + OPTION_V3_PRESSURE_UNITS_METERS, + OPTION_V3_PRESSURE_UNITS_PSI, + OPTION_V3_QUALITY_MODEL_CHEMICAL, + OPTION_V3_QUALITY_MODEL_NONE, + OPTION_V3_QUALITY_MODEL_TRACE, + OPTION_V3_QUALITY_UNITS_HRS, + OPTION_V3_QUALITY_UNITS_MGL, + OPTION_V3_STEP_SIZING_FULL, + OPTION_V3_STEP_SIZING_RELAXATION, + OVERFLOW_NO, + OVERFLOW_YES, + PATTERN, + PIPE, + PIPE_STATUS_CLOSED, + PIPE_STATUS_OPEN, + PUMP, + RESERVOIR, + SCADA_DEVICE_TYPE_FLOW, + SCADA_DEVICE_TYPE_PRESSURE, + SCADA_ELEMENT_STATUS_OFFLINE, + SCADA_ELEMENT_STATUS_ONLINE, + SCADA_MODEL_TYPE_JUNCTION, + SCADA_MODEL_TYPE_PIPE, + SOURCE_TYPE_CONCEN, + SOURCE_TYPE_FLOWPACED, + TAG_TYPE_LINK, + TAG_TYPE_NODE, + TANK, + TIME_STATISTIC_AVERAGED, + TIME_STATISTIC_NONE, + VALVE, + VALVES_TYPE_FCV, + VALVES_TYPE_GPV, + add_curve, + add_district_metering_area, + add_junction, + add_label, + add_mixing, + add_pattern, + add_pipe, + add_pump, + add_region, + add_reservoir, + add_scada_device, + add_scada_device_data, + add_scada_element, + add_service_area, + add_source, + add_tank, + add_valve, + add_virtual_district, + calculate_boundary, + calculate_convex_hull, + calculate_demand_to_network, + calculate_demand_to_nodes, + calculate_demand_to_region, + calculate_district_metering_area_for_network, + calculate_district_metering_area_for_nodes, + calculate_district_metering_area_for_region, + calculate_service_area, + calculate_virtual_district, + clean_scada_device, + clean_scada_device_data, + clean_scada_element, + close_project, + create_project, + delete_curve, + delete_district_metering_area, + delete_junction, + delete_label, + delete_mixing, + delete_pattern, + delete_pipe, + delete_project, + delete_pump, + delete_region, + delete_reservoir, + delete_scada_device, + delete_scada_device_data, + delete_scada_element, + delete_service_area, + delete_source, + delete_tank, + delete_valve, + delete_virtual_district, + execute_batch_command, + execute_batch_commands, + execute_redo, + execute_undo, + generate_district_metering_area, + generate_service_area, + generate_sub_district_metering_area, + generate_virtual_district, + get_all_district_metering_area_ids, + get_all_extension_data, + get_all_extension_data_keys, + get_all_scada_device_ids, + get_all_scada_element_ids, + get_all_service_area_ids, + get_all_service_areas, + get_all_virtual_district_ids, + get_all_virtual_districts, + get_backdrop, + get_control, + get_current_operation, + get_curve, + get_demand, + get_district_metering_area, + get_emitter, + get_energy, + get_extension_data, + get_junction, + get_label, + get_links, + get_links_on_region_boundary, + get_mixing, + get_node_links, + get_nodes, + get_nodes_in_boundary, + get_nodes_in_region, + get_operation_by_snapshot, + get_option, + get_option_v3, + get_pattern, + get_pipe, + get_pipe_reaction, + get_pump, + get_pump_energy, + get_quality, + get_reaction, + get_region, + get_reservoir, + get_restore_operation, + get_rule, + get_scada_device, + get_scada_device_data, + get_scada_element, + get_service_area, + get_snapshot_by_operation, + get_source, + get_status, + get_tag, + get_tags, + get_tank, + get_tank_reaction, + get_time, + get_title, + get_valve, + get_vertex, + get_virtual_district, + have_project, + inflate_boundary, + inflate_region, + is_curve, + is_junction, + is_link, + is_node, + is_pattern, + is_pipe, + is_project_open, + is_pump, + is_reservoir, + is_tank, + is_valve, + open_project, + pick_operation, + pick_snapshot, + read_all, + read_inp, + set_backdrop, + set_control, + set_curve, + set_demand, + set_district_metering_area, + set_emitter, + set_energy, + set_extension_data, + set_junction, + set_label, + set_mixing, + set_option, + set_option_v3, + set_pattern, + set_pipe, + set_pipe_reaction, + set_pump, + set_pump_energy, + set_quality, + set_reaction, + set_region, + set_reservoir, + set_rule, + set_scada_device, + set_scada_device_data, + set_scada_element, + set_service_area, + set_source, + set_status, + set_tag, + set_tank, + set_tank_reaction, + set_time, + set_title, + set_valve, + set_vertex, + set_virtual_district, + sync_with_server, + take_snapshot, + update_snapshot_for_current_operation, + write, +) class TestApi: def enter(self, p): diff --git a/sensor_placement.py b/sensor_placement.py deleted file mode 100644 index 2782db9..0000000 --- a/sensor_placement.py +++ /dev/null @@ -1,557 +0,0 @@ -# 改进灵敏度法 -import networkx -import numpy as np -import pandas -import wntr -import pandas as pd -import copy -import matplotlib.pyplot as plt -import networkx as nx -from sklearn.cluster import KMeans -from wntr.epanet.toolkit import EpanetException -from numpy.linalg import slogdet -import random -from tjnetwork import * -import project_info - -# 2025/03/12 -# Step1: 获取节点坐标 -def getCoor(wn: wntr.network.WaterNetworkModel) -> pandas.DataFrame: - """ - 获取管网模型的节点坐标 - :param wn: 由wntr生成的模型 - :return: 节点坐标 - """ - # site: pandas.Series - # index:节点名称(wn.node_name_list) - # values:每个节点的坐标,格式为 tuple(如 (x, y) 或 (x, y, z)) - site = wn.query_node_attribute('coordinates') - # Coor: pandas.Series - # index:与site相同(节点名称)。 - # values:坐标转换为numpy.ndarray(如array([10.5, 20.3])) - Coor = site.apply(lambda x: np.array(x)) # 将节点坐标转换为numpy数组 - # x, y: list[float] - x = [] # 存储所有节点的 x 坐标 - y = [] # 存储所有节点的 y 坐标 - for i in range(0, len(Coor)): - x.append(Coor.values[i][0]) # 将 x 坐标存入 x 列表。 - y.append(Coor.values[i][1]) # 将 y 坐标存入 y 列表 - # xy: dict[str, list], x、y 坐标的字典 - xy = {'x': x, 'y': y} - # Coor_node: pandas.DataFrame, 存储节点 x, y 坐标的 DataFrame - Coor_node = pd.DataFrame(xy, index=wn.node_name_list, columns=['x', 'y']) - return Coor_node - - -# 2025/03/12 -# Step2: KMeans 聚类 -# 将节点用kmeans根据坐标分为k组,存入字典g -def kgroup(coor: pandas.DataFrame, knum: int) -> dict[int, list[str]]: - """ - 使用KMeans聚类,将节点坐标分组 - :param coor: 存储所有节点的坐标数据 - :param knum: 需要分成的聚类数 - :return: 聚类结果字典 - """ - g = {} - # estimator: sklearn.cluster.KMeans,KMeans 聚类模型 - estimator = KMeans(n_clusters=knum) - estimator.fit(coor) - # label_pred: numpy.ndarray(int),每个点的类别标签 - label_pred = estimator.labels_ - for i in range(0, knum): - g[i] = coor[label_pred == i].index.tolist() - return g - - -# 2025/03/12 -# Step3: wn_func类,水力计算 -# wn_func 主要用于计算: -# 水力距离(hydraulic length):即节点之间的水力阻力。 -# 灵敏度分析(sensitivity analysis):用于优化测压点的布置。 -# 一些与水力相关的函数,包括 CtoS:求水力距离,stafun:求状态函数F -# # diff:求F对P的导数,返回灵敏度矩阵A -# # sensitivity:返回灵敏度和总灵敏度 -class wn_func(object): - - # Step3.1: 初始化 - def __init__(self, wn: wntr.network.WaterNetworkModel): - """ - 获取管网模型信息 - :param wn: 由wntr生成的模型 - """ - # self.results: wntr.sim.results.SimulationResults,仿真结果,包含压力、流量、水头等数据 - self.results = wntr.sim.EpanetSimulator(wn).run_sim() # 存储运行结果 - self.wn = wn - # self.q:pandas.DataFrame,管道流量,索引为时间步长,列为管道名称 - self.q = self.results.link['flowrate'] - # ReservoirIndex / Tankindex: list[str],水库 / 水箱节点名称列表 - ReservoirIndex = wn.reservoir_name_list - Tankindex = wn.tank_name_list - # 删除水库节点,删除与直接水库相连的虚拟管道 - # self.pipes: list[str],所有管道的名称 - self.pipes = wn.pipe_name_list - # self.nodes: list[str],所有节点的名称 - self.nodes = wn.node_name_list - # self.coordinates:pandas.Series,节点坐标,索引为节点名,值为 (x, y) 坐标的 tuple - self.coordinates = wn.query_node_attribute('coordinates') - # allpumps / allvalves: list[str],所有泵/阀门名称列表 - allpumps = wn.pump_name_list - allvalves = wn.valve_name_list - # pumpstnode / pumpednode / valvestnode / valveednode: list[str],存储泵和阀门 起终点节点的名称 - pumpstnode = [] - pumpednode = [] - valvestnode = [] - valveednode = [] - # Reservoirpipe / Reservoirednode: list[str],记录与水库相关的管道和节点 - Reservoirpipe = [] - Reservoirednode = [] - for pump in allpumps: - pumpstnode.append(wn.links[pump].start_node.name) - pumpednode.append(wn.links[pump].end_node.name) - for valve in allvalves: - valvestnode.append(wn.links[valve].start_node.name) - valveednode.append(wn.links[valve].end_node.name) - for pipe in self.pipes: - if wn.links[pipe].start_node.name in ReservoirIndex: - Reservoirpipe.append(pipe) - Reservoirednode.append(wn.links[pipe].end_node.name) - if wn.links[pipe].start_node.name in Tankindex: - Reservoirpipe.append(pipe) - Reservoirednode.append(wn.links[pipe].end_node.name) - if wn.links[pipe].end_node.name in Tankindex: - Reservoirpipe.append(pipe) - Reservoirednode.append(wn.links[pipe].start_node.name) - # 泵的起终点、tank、reservoir - # self.delnodes: list[str],需要删除的节点(包括水库、泵、阀门连接的节点) - self.delnodes = list( - set(ReservoirIndex).union(Tankindex, pumpstnode, pumpednode, valvestnode, valveednode, Reservoirednode)) - # 泵、起终点为tank、reservoir的管道 - # self.delpipes: list[str],需要删除的管道(包括水库、泵、阀门连接的管道) - self.delpipes = list(set(wn.pump_name_list).union(wn.valve_name_list).union(Reservoirpipe)) - self.pipes = [pipe for pipe in wn.pipe_name_list if pipe not in self.delpipes] - # self.L: list[float],所有管道的长度(以米为单位) - self.L = wn.query_link_attribute('length')[self.pipes].tolist() - self.n = len(self.nodes) - self.m = len(self.pipes) - # self.unit_headloss: list[float],单位水头损失(headloss 数据的第一行,单位:米/km) - self.unit_headloss = self.results.link['headloss'].iloc[0, :].tolist() - ## - self.delnodes1 = list(set(ReservoirIndex).union(Tankindex)) - - # Step3.2: 计算水力距离 - def CtoS(self): - """ - 计算水力距离矩阵 - :return: - """ - # 水力距离:当行索引对应的节点为控制点时,列索引对应的节点距离控制点的(路径*水头损失)的最小值 - # nodes:list[str](节点名称) - nodes = copy.deepcopy(self.nodes) - # pipes:list[str](管道名称) - pipes = self.pipes - wn = self.wn - # n / m:int(节点数 / 管道数) - n = self.n - m = self.m - s1 = [0] * m - q = self.q - L = self.L - # H1:pandas.DataFrame,水头数据,索引为时间步长,列为节点名 - H1 = self.results.node['head'].T - # hh:list[float],计算管道两端水头之差 - hh = [] - # 水头损失 - for p in pipes: - h1 = self.wn.links[p].start_node.name - h1 = H1.loc[str(h1)] - h2 = self.wn.links[p].end_node.name - h2 = H1.loc[str(h2)] - hh.append(abs(h1 - h2)) - hh = np.array(hh) - # headloss:pandas.DataFrame,管道水头损失矩阵 - headloss = pd.DataFrame(hh, index=pipes).T - # s1:管道阻力系数,s2:将管道阻力系数与管道的起始节点和终止节点对应 - hf = pd.DataFrame(np.array([0] * (n ** 2)).reshape(n, n), index=nodes, columns=nodes, dtype=float) - weightL = pd.DataFrame(np.array([0] * (n ** 2)).reshape(n, n), index=nodes, columns=nodes, dtype=float) - # s2为对应管道起始节点与终止节点的粗糙度系数矩阵,index代表起始节点,columns代表终止节点 - G = nx.DiGraph() - for i in range(0, m): - pipe = pipes[i] - a = wn.links[pipe].start_node.name - b = wn.links[pipe].end_node.name - if q.loc[0, pipe] > 0: - hf.loc[a, b] = headloss.loc[0, pipe] - weightL.loc[a, b] = headloss.loc[0, pipe] * L[i] - G.add_weighted_edges_from([(a, b, weightL.loc[a, b])]) - - else: - hf.loc[b, a] = headloss.loc[0, pipe] - weightL.loc[b, a] = headloss.loc[0, pipe] * L[i] - G.add_weighted_edges_from([(b, a, weightL.loc[b, a])]) - - hydraulicL = pd.DataFrame(np.array([0] * (n ** 2)).reshape(n, n), index=nodes, columns=nodes, dtype=float) - - for a in nodes: - if a in G.nodes: - d = nx.shortest_path_length(G, source=a, weight='weight') - for b in list(d.keys()): - hydraulicL.loc[a, b] = d[b] - - hydraulicL = hydraulicL.drop(self.delnodes) - hydraulicL = hydraulicL.drop(self.delnodes, axis=1) - - # 求加权水力距离 - return hydraulicL, G - - # Step3.3: 计算灵敏度矩阵 - # 获取关系矩阵 - def get_Conn(self): - """ - 计算管网连接关系矩阵 - :return: - """ - m = self.wn.num_links - n = self.wn.num_nodes - p = self.wn.num_pumps - v = self.wn.num_valves - - self.nonjunc_index = [] - self.non_link_index = [] - for r in self.wn.reservoirs(): - self.nonjunc_index.append(r[0]) - for t in self.wn.tanks(): - self.nonjunc_index.append(t[0]) - # Conn:numpy.matrix,节点-管道连接矩阵,起点 -1,终点 1 - Conn = np.mat(np.zeros([n, m - p - v])) # 节点和管道的关系矩阵,行为节点,列为管道,起点为-1,终点为1 - # NConn:numpy.matrix,节点-节点连接矩阵,有管道相连的地方设为 1 - NConn = np.mat(np.zeros([n, n])) # 节点之间的关系,之间有管道为1,反之为0 - # pipes:list[str],去除泵和阀门的管道列表 - pipes = [pipe for pipe in self.wn.pipes() if pipe not in self.wn.pumps() and pipe not in self.wn.valves()] - for pipe_name, pipe in pipes: - start = self.wn.node_name_list.index(pipe.start_node_name) - end = self.wn.node_name_list.index(pipe.end_node_name) - p_index = self.wn.link_name_list.index(pipe_name) - Conn[start, p_index] = -1 - Conn[end, p_index] = 1 - NConn[start, end] = 1 - NConn[end, start] = 1 - self.A = Conn - link_name_list = [link for link in self.wn.link_name_list if - link not in self.wn.pump_name_list and link not in self.wn.valve_name_list] - self.A2 = pd.DataFrame(self.A, index=self.wn.node_name_list, columns=link_name_list) - self.A2 = self.A2.drop(self.delnodes) - for pipe in self.delpipes: - if pipe not in self.wn.pump_name_list and pipe not in self.wn.valve_name_list: - self.A2 = self.A2.drop(columns=pipe) - self.junc_list = self.A2.index - self.A2 = np.mat(self.A2) # 节点管道关系 - self.A3 = NConn - - def Jaco(self, hL: pandas.DataFrame): - """ - 计算灵敏度矩阵(节点压力对粗糙度变化的响应) - :param hL: 水力距离矩阵 - :return: - """ - # global result - # A:numpy.matrix, 节点-管道关系矩阵 - A = self.A2 - wn = self.wn - - try: - result = wntr.sim.EpanetSimulator(wn).run_sim() - except EpanetException: - pass - finally: - h = result.link['headloss'][self.pipes].values[0] - q = result.link['flowrate'][self.pipes].values[0] - l = self.wn.query_link_attribute('length')[self.pipes] - C = self.wn.query_link_attribute('roughness')[self.pipes] - # headloss:numpy.ndarray,水头损失数组 - headloss = np.array(h) - # 调整流量方向 - for i in range(0, len(q)): - if q[i] < 0: - A[:, i] = -A[:, i] - # q:numpy.ndarray,流量数组 - q = np.abs(q) - # 两个灵敏度矩阵 - # B / S:numpy.matrix,灵敏度计算的中间矩阵 - B = np.mat(np.diag(q / ((1.852 * headloss) + 1e-10))) - S = np.mat(np.diag(q / C)) - # X:numpy.matrix, 灵敏度矩阵 - X = A * B * A.T - try: - det = np.linalg.det(X) - except RuntimeError as e: - sign, logdet = slogdet(X) # 防止溢出 - det = sign * np.exp(logdet) - if det != 0: - J_H_Cw = X.I * A * S - # J_H_Q = -X.I - J_q_Cw = S - B * A.T * X.I * A * S # 去掉了delnodes和delpipes - # J_q_Q = B * A.T * X.I - else: # 当X不可逆 - J_H_Cw = np.linalg.pinv(X) @ A @ S - # J_H_Q = -np.linalg.pinv(X) - J_q_Cw = S - B * A.T * np.linalg.pinv(X) * A * S - # J_q_Q = B * A.T * np.linalg.pinv(X) - - Sen_pressure = [] - S_pressure = np.abs(J_H_Cw).sum(axis=1).tolist() # 修改为绝对值 - for ss in S_pressure: - Sen_pressure.append(ss[0]) - # 求总灵敏度 - SS_pressure = copy.deepcopy(hL) - for i in range(0, len(Sen_pressure)): - SS_pressure.iloc[i, :] = SS_pressure.iloc[i, :] * Sen_pressure[i] - SS = copy.deepcopy(hL) - for i in range(0, len(Sen_pressure)): - SS.iloc[i, :] = SS.iloc[i, :] * Sen_pressure[i] - # SS[i,j]:节点nodes[i]的灵敏度*该节点到nodes[j]的水力距离 - return SS - - -# 2025/03/12 -# Step4: 传感器布置优化 -# Sensorplacement -# weight:分配权重 -# sensor:传感器布置的位置 -class Sensorplacement(wn_func): - """ - Sensorplacement 类继承了 wn_func 类,并且用于计算和优化传感器布置的位置。 - """ - def __init__(self, wn: wntr.network.WaterNetworkModel, sensornum: int): - """ - - :param wn: 由wntr生成的模型 - :param sensornum: 传感器的数量 - """ - wn_func.__init__(self, wn) - self.sensornum = sensornum - - # 1.某个节点到所有节点的加权距离之和 - # 2.某个节点到该组内所有节点的加权距离之和 - def sensor(self, SS: pandas.DataFrame, G: networkx.Graph, group: dict[int, list[str]]): - """ - sensor 方法是用来根据灵敏度矩阵 SS 和加权图 G 来确定传感器布置位置的 - :param SS: 灵敏度矩阵,每个节点的行和列代表不同节点,矩阵元素表示节点间的灵敏度。SS.iloc[i, :] 表示第 i 行对应节点 i 到所有其他节点的灵敏度 - :param G: 加权图,表示管网的拓扑结构,每个节点通过管道连接。图的边的权重通常是根据水力距离或者流量等计算的 - :param group: 节点分组,字典的键是分组编号,值是该组的节点名称列表 - :return: - """ - # 传感器布置个数以及位置 - # W = self.weight() - n = self.n - len(self.delnodes) - nodes = copy.deepcopy(self.nodes) - for node in self.delnodes: - nodes.remove(node) - # sumSS:list[float],每个节点到其他节点的灵敏度之和。SS.iloc[i, :] 返回第 i 个节点与所有其他节点的灵敏度值,sum(SS.iloc[i, :]) 计算这些灵敏度值的总和。 - sumSS = [] - for i in range(0, n): - sumSS.append(sum(SS.iloc[i, :])) - # 一个整数范围,表示每个节点的索引,用作sumSS_ DataFrame的索引 - indices = range(0, n) - # sumSS_:pandas.DataFrame,将 sumSS 转换成 DataFrame 格式,并且将节点的总灵敏度保存到 CSV 文件 sumSS_data.csv 中 - sumSS_ = pd.DataFrame(np.array(sumSS), index=indices) - sumSS_.to_csv('sumSS_data.csv') # 存储节点总灵敏度 - # sumSS:pandas.DataFrame,sumSS 被转换为 DataFrame 类型,并且按总灵敏度(即灵敏度之和)降序排列。此时,sumSS 是按节点的灵敏度之和排序的 DataFrame - sumSS = pd.DataFrame(np.array(sumSS), index=nodes) - sumSS = sumSS.sort_values(by=[0], ascending=[False]) - # sensorindex:list[str],用于存储根据灵敏度排序选出的传感器位置的节点名称,存储根据总灵敏度排序的节点列表,用于传感器布置 - sensorindex = [] - # sensorindex_2:list[str],用于存储每组内根据灵敏度排序选出的传感器位置的节点名称,存储每个组内根据灵敏度排序选择的传感器节点 - sensorindex_2 = [] - # group_S:dict[int, pandas.DataFrame],存储每个组内的灵敏度矩阵 - group_S = {} - # group_sumSS:dict[int, list[float]],存储每个组内节点的总灵敏度,值为每个组内节点灵敏度之和的列表 - group_sumSS = {} - for i in range(0, len(group)): - for node in self.delnodes: - # 这里的group[i]是每个组的节点列表,代码首先去除已经被标记为删除的节点self.delnodes - if node in group[i]: - group[i].remove(node) - group_S[i] = SS.loc[group[i], group[i]] - # 对每个组内的节点,计算组内节点的总灵敏度(group_sumSS[i])。它将每个组内节点的灵敏度值相加,并且按灵敏度降序排序 - group_sumSS[i] = [] - for j in range(0, len(group[i])): - group_sumSS[i].append(sum(group_S[i].iloc[j, :])) - group_sumSS[i] = pd.DataFrame(np.array(group_sumSS[i]), index=group[i]) - group_sumSS[i] = group_sumSS[i].sort_values(by=[0], ascending=[False]) - pass - - # 1.选sumSS最大的节点,然后把这个节点所在的那个组删掉,就可以不再从这个组选点。再重新排序选sumSS最大的; - # 2.在每组内选group_sumSS最大的节点 - # 在这个循环中,首先选择灵敏度最高的节点Smaxnode并添加到sensorindex。然后根据灵敏度排序,删除已选的节点并继续选择下一个灵敏度最大的节点。这个过程用于选择传感器的位置 - sensornum = self.sensornum - for i in range(0, sensornum): - # Smaxnode:str,最大灵敏度节点,sumSS.index[0] 表示灵敏度最高的节点 - Smaxnode = sumSS.index[0] - sensorindex.append(Smaxnode) - sensorindex_2.append(group_sumSS[i].index[0]) - - for key, value in group.items(): - if Smaxnode in value: - sumSS = sumSS.drop(index=group[key]) - continue - - sumSS = sumSS.sort_values(by=[0], ascending=[False]) - - return sensorindex, sensorindex_2 - - -# 2025/03/13 -def get_sensor_coord(name: str, sensor_num: int) -> dict[str, float]: - """ - 获取布置测压点的坐标,初始测压点布置根据灵敏度来布置,计算初始情况下的校准过程的error - :param name: 数据库名称 - :param sensor_num: 测压点数目 - :return: 测压点坐标字典 - """ - # inp_file_real:str,输入文件名,表示原始水力模型文件的路径,该文件格式为 EPANET 输入文件(.inp),包含管网的结构信息、节点、管道、泵等数据 - inp_file_real = f'./db_inp/{name}.db.inp' - # sensornum:int,需要布置的传感器数量 - # sensornum = sensor_num - # wn_real:wntr.network.WaterNetworkModel,加载 EPANET 水力模型 - wn_real = wntr.network.WaterNetworkModel(inp_file_real) # 真实粗糙度的原始管网 - # sim_real:wntr.sim.EpanetSimulator,创建一个水力仿真器对象 - sim_real = wntr.sim.EpanetSimulator(wn_real) - # results_real:wntr.sim.results.SimulationResults,运行仿真并返回结果 - results_real = sim_real.run_sim() - - # real_C:list[float],包含所有管道粗糙度的列表 - real_C = wn_real.query_link_attribute('roughness').tolist() - # wn_fun1:wn_func(继承自 object),创建 wn_func 类的实例,传入 wn_real 水力模型对象。wn_func 用于计算管网相关的水力属性,比如水力距离、灵敏度等 - wn_fun1 = wn_func(wn_real) - # nodes:list[str],管网的节点名称列表 - nodes = wn_fun1.nodes - # delnodes:list[str],被删除的节点(如水库、泵、阀门连接的节点等) - delnodes = wn_fun1.delnodes - # Coor_node:pandas.DataFrame - Coor_node = getCoor(wn_real) - Coor_node = Coor_node.drop(wn_fun1.delnodes) - nodes = [node for node in wn_fun1.nodes if node not in delnodes] - # coordinates:pandas.Series,存储所有节点的坐标,类型为 Series,索引为节点名称,值为 (x, y) 坐标对 - coordinates = wn_fun1.coordinates - - # 随机产生监测点 - # junctionnum:int,nodes 的长度,表示节点的数量 - junctionnum = len(nodes) - # random_numbers:list[int],使用 random.sample 随机选择 sensornum(20)个节点的编号。它返回一个不重复的随机编号列表 - # random_numbers = random.sample(range(junctionnum), sensor_num) - # for i in range(sensor_num): - # # print(random_numbers[i]) - - wn_fun1.get_Conn() - # hL:pandas.DataFrame,水力距离矩阵,表示每个节点到其他节点的水力阻力 - # G:networkx.DiGraph,加权有向图,表示管网的拓扑结构,节点之间的边带有权重 - hL, G = wn_fun1.CtoS() - # SS:pandas.DataFrame,灵敏度矩阵,表示每个节点对管网变化(如粗糙度、流量等)的响应 - SS = wn_fun1.Jaco(hL) - # group:dict[int, list[str]],使用 kgroup 函数将节点按坐标分成若干组,每组包含的节点数不一定相同。group 是一个字典,键为分组编号,值为节点名列表 - group = kgroup(Coor_node, sensor_num) - # wn_fun:Sensorplacement(继承自wn_func) - # 创建Sensorplacement类的实例,传入水力网络模型wn_real和传感器数量sensornum。Sensorplacement用于计算和布置传感器 - wn_fun = Sensorplacement(wn_real, sensor_num) - wn_fun.__dict__.update(wn_fun1.__dict__) - # sensorindex:list[str],初始传感器布置位置的节点名称 - # sensorindex_2:list[str],根据分组选择的传感器位置 - sensorindex, sensorindex_2 = wn_fun.sensor(SS, G, group) # 初始的sensorindex - # print(str(sensor_num), "个测压点,测压点位置:", sensorindex) - sensor_coord = {} - # 重新打开数据库 - if is_project_open(name=name): - close_project(name=name) - open_project(name=name) - for node_id in sensorindex: - sensor_coord[node_id] = get_node_coord(name=name, node_id=node_id) - close_project(name=name) - # print(sensor_coord) - return sensor_coord - - -if __name__ == '__main__': - sensor_coord = get_sensor_coord(name=project_info.name, sensor_num=20) - print(sensor_coord) - # ''' - # 初始测压点布置根据灵敏度来布置,计算初始情况下的校准过程的error - # ''' - # - # # inp_file_real:str,输入文件名,表示原始水力模型文件的路径,该文件格式为 EPANET 输入文件(.inp),包含管网的结构信息、节点、管道、泵等数据 - # inp_file_real = './db_inp/bb.db.inp' - # # sensornum:int,需要布置的传感器数量 - # sensornum = 20 - # # wn_real:wntr.network.WaterNetworkModel,加载 EPANET 水力模型 - # wn_real = wntr.network.WaterNetworkModel(inp_file_real) # 真实粗糙度的原始管网 - # # sim_real:wntr.sim.EpanetSimulator,创建一个水力仿真器对象 - # sim_real = wntr.sim.EpanetSimulator(wn_real) - # # results_real:wntr.sim.results.SimulationResults,运行仿真并返回结果 - # results_real = sim_real.run_sim() - # - # # real_C:list[float],包含所有管道粗糙度的列表 - # real_C = wn_real.query_link_attribute('roughness').tolist() - # # wn_fun1:wn_func(继承自 object),创建 wn_func 类的实例,传入 wn_real 水力模型对象。wn_func 用于计算管网相关的水力属性,比如水力距离、灵敏度等 - # wn_fun1 = wn_func(wn_real) - # # nodes:list[str],管网的节点名称列表 - # nodes = wn_fun1.nodes - # # delnodes:list[str],被删除的节点(如水库、泵、阀门连接的节点等) - # delnodes = wn_fun1.delnodes - # # Coor_node:pandas.DataFrame - # Coor_node = getCoor(wn_real) - # Coor_node = Coor_node.drop(wn_fun1.delnodes) - # nodes = [node for node in wn_fun1.nodes if node not in delnodes] - # # coordinates:pandas.Series,存储所有节点的坐标,类型为 Series,索引为节点名称,值为 (x, y) 坐标对 - # coordinates = wn_fun1.coordinates - # - # # 随机产生监测点 - # # junctionnum:int,nodes 的长度,表示节点的数量 - # junctionnum = len(nodes) - # # random_numbers:list[int],使用 random.sample 随机选择 sensornum(20)个节点的编号。它返回一个不重复的随机编号列表 - # random_numbers = random.sample(range(junctionnum), sensornum) - # for i in range(sensornum): - # print(random_numbers[i]) - # - # wn_fun1.get_Conn() - # # hL:pandas.DataFrame,水力距离矩阵,表示每个节点到其他节点的水力阻力 - # # G:networkx.DiGraph,加权有向图,表示管网的拓扑结构,节点之间的边带有权重 - # hL, G = wn_fun1.CtoS() - # # SS:pandas.DataFrame,灵敏度矩阵,表示每个节点对管网变化(如粗糙度、流量等)的响应 - # SS = wn_fun1.Jaco(hL) - # # group:dict[int, list[str]],使用 kgroup 函数将节点按坐标分成若干组,每组包含的节点数不一定相同。group 是一个字典,键为分组编号,值为节点名列表 - # group = kgroup(Coor_node, sensornum) - # # wn_fun:Sensorplacement(继承自wn_func) - # # 创建Sensorplacement类的实例,传入水力网络模型wn_real和传感器数量sensornum。Sensorplacement用于计算和布置传感器 - # wn_fun = Sensorplacement(wn_real, sensornum) - # wn_fun.__dict__.update(wn_fun1.__dict__) - # # sensorindex:list[str],初始传感器布置位置的节点名称 - # # sensorindex_2:list[str],根据分组选择的传感器位置 - # sensorindex, sensorindex_2 = wn_fun.sensor(SS, G, group) # 初始的sensorindex - # print(str(sensornum), "个测压点,测压点位置:", sensorindex) - - # # 分区画图 - # colorlist = ['lightpink', 'coral', 'rosybrown', 'olive', 'powderblue', 'lightskyblue', 'steelblue', 'peachpuff','brown','silver','indigo','lime','gold','violet','maroon','navy','teal','magenta','cyan', - # 'burlywood', 'tan', 'slategrey', 'thistle', 'lightseagreen', 'lightgreen', 'red','blue','yellow','orange','purple','grey','green','pink','lightblue','beige','chartreuse','turquoise','lavender','fuchsia','coral'] - # G = wn_real.to_graph() - # G = G.to_undirected() # 变为无向图 - # pos = nx.get_node_attributes(G, 'pos') - # pass - # for i in range(0, sensornum): - # ax = plt.gca() - # ax.set_title(inp_file_real + str(sensornum)) - # nodes = nx.draw_networkx_nodes(G, pos, nodelist=group[i], node_color=colorlist[i], node_size=20) - # nodes = nx.draw_networkx_nodes(G, pos, - # nodelist=sensorindex_2, node_color='black', node_size=70, node_shape='*' - # ) - # edges = nx.draw_networkx_edges(G, pos) - # ax.spines['top'].set_visible(False) - # ax.spines['right'].set_visible(False) - # ax.spines['bottom'].set_visible(False) - # ax.spines['left'].set_visible(False) - # plt.savefig(inp_file_real + str(sensornum) + ".png") - # plt.show() - # - # wntr.graphics.plot_network(wn_real, node_attribute=sensorindex_2, node_size=50, node_labels=False, - # title=inp_file_real + '_Projetion' + str(sensornum)) - # plt.savefig(inp_file_real + '_S' + str(sensornum) + ".png") - # plt.show() \ No newline at end of file diff --git a/setup_influxdb.md b/setup_influxdb.md deleted file mode 100644 index e4d6929..0000000 --- a/setup_influxdb.md +++ /dev/null @@ -1,14 +0,0 @@ -Setup instructions for WMH's work - -1. import scada_info.csv - run python online_Analysis.py - -2. import history_pattern_flow.csv - run python online_Analysis.py - Should manually change code - -3. run create_template.py - -4. run influxdb_api.py - 在InfluxDB数据库中创建好我们需要的bucket - create buckets \ No newline at end of file diff --git a/setup_server.md b/setup_server.md deleted file mode 100644 index 23bd4e1..0000000 --- a/setup_server.md +++ /dev/null @@ -1,90 +0,0 @@ -搭建服务器 - -1. `git clone https://e.coding.net/tjwater/tjwatercloud/TJWaterServer.git` -2. 控制台进入 `TJWaterServer` -3. 运行 `python install.py` 准备Python环境 -3.1 Python 3.12 需要手动的安装(拷贝) PyMetis 库 -4. 解压 `pg14.zip` 到上一层文件夹 -5. 控制台进入 `../pg14/bin` -5.1 将pg14/bin 加到系统PATH中,这步一定需要做,CopyProjectEx里需要这个 -6. 执行 `initdb -D ../data -E UTF-8` 创建数据库 -7. 执行 `pg_ctl -D ../data -l logfile start` 启动数据库服务 - - `pg_ctl -D ../data -l logfile stop` 关闭数据库服务 -8. 进入 `TJWaterServer`,执行 `python create_template.py` 创建模板 -9. 执行 `python online_Analysis.py` -10. 执行 `python influxdb_api.py` -11. 搭建FastAPI环境... -12. 进入 `TJWaterServer`,执行 `startserber.bat` - -NOTE: - 版本问题 - pip uninstall scipy numpy -y - pip install numpy==1.26.2 scipy==1.15.2 - -pg 信息 - 腾讯Windows服务器 - Host: localhost (默认) - Port: 5432 (默认) - User: 就是Windows的用户名,这台机器也就是 Administrator - Password: 密码为空 - -redis 信息 - - 1. 进到redis安装目录 - 2. 执行 redis-server.exe - - - -influx db 信息 - 1. 运行 influxd.exe - 2. 打开网页看下列的信息 http://localhost:8086 - - # influxdb数据库连接信息 - influx_url = "http://localhost:8086" # 替换为你的InfluxDB实例地址 - influx_token = "Vq8F5tzxqmjH6JYPBP5xqwo6nJbzRqCnahlcoMVyZGMPm3H92swD08VX-5lTH1laN_JG1x7EZ80WOQoycanmBw==" # 替换为你的InfluxDB Token - influx_org_name = "TJWATERORG" # 替换为你的Organization名称 - influx_client = InfluxDBClient(url=influx_url, token=influx_token, org=influx_org_name) - - -UserName tjwater -Password Tjwater@123456 -Organizatio TJWATEORG -Bucket TJWATERBUCKET - -API Token : LsqvuqtBqtBv44z_CWh5bWfn9hs1QKcYu5kWahF_cdF6JyqtwuUxU5CK7HWP7BOtP5_2f5mjx76qXyuPLOHWdw== - -influx config create --config-name onboarding ` - --host-url "http://localhost:8086" ` - --org "TJWATERORG" ` - --token "LsqvuqtBqtBv44z_CWh5bWfn9hs1QKcYu5kWahF_cdF6JyqtwuUxU5CK7HWP7BOtP5_2f5mjx76qXyuPLOHWdw==" - --active - - -Setup instructions for WMH's work - -1. import scada_info.csv - run python online_Analysis.py - -2. import history_pattern_flow.csv - run python online_Analysis.py - Should manually change code - -3. run create_template.py - -4. run influxdb_api.py - 在InfluxDB数据库中创建好我们需要的bucket - create buckets - -5. run online_Analysis.py - 有几个步骤 - (1)创建用户名密码 - (2)network_update 从 inp 文件创建 szh这个project - (3)upload_shp_to_pg - (4)submit_risk_probability_result - (5)pressure_sensor_placement_sensitivity - -6. In times table, all time values should be the format "hh:mm::ss" - -NOTES: - 1. SCADA设备的时候,单位要转换,现在模拟算出来的单位是L/s,SCADA数据是m3/h,L/s要乘3.6才是m3/h - 2. 之前的SCADA压力应该转过了,SCADA数据的单位是MPa,要乘以100才是m \ No newline at end of file diff --git a/software/pg14/pg14.z01 b/software/pg14/pg14.z01 deleted file mode 100644 index 60738c5..0000000 Binary files a/software/pg14/pg14.z01 and /dev/null differ diff --git a/software/pg14/pg14.z02 b/software/pg14/pg14.z02 deleted file mode 100644 index 7df62bb..0000000 Binary files a/software/pg14/pg14.z02 and /dev/null differ diff --git a/software/pg14/pg14.z03 b/software/pg14/pg14.z03 deleted file mode 100644 index 4cc4179..0000000 Binary files a/software/pg14/pg14.z03 and /dev/null differ diff --git a/software/pg14/pg14.z04 b/software/pg14/pg14.z04 deleted file mode 100644 index 2b69c53..0000000 Binary files a/software/pg14/pg14.z04 and /dev/null differ diff --git a/software/pg14/pg14.z05 b/software/pg14/pg14.z05 deleted file mode 100644 index 57dcaec..0000000 Binary files a/software/pg14/pg14.z05 and /dev/null differ diff --git a/software/pg14/pg14.z06 b/software/pg14/pg14.z06 deleted file mode 100644 index 5eb36ed..0000000 Binary files a/software/pg14/pg14.z06 and /dev/null differ diff --git a/software/pg14/pg14.z07 b/software/pg14/pg14.z07 deleted file mode 100644 index b1afbc8..0000000 Binary files a/software/pg14/pg14.z07 and /dev/null differ diff --git a/software/pg14/pg14.zip b/software/pg14/pg14.zip deleted file mode 100644 index 06ac07d..0000000 Binary files a/software/pg14/pg14.zip and /dev/null differ diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/api/test_api_integration.py b/tests/api/test_api_integration.py new file mode 100755 index 0000000..741555c --- /dev/null +++ b/tests/api/test_api_integration.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +""" +测试新增 API 集成 + +验证新的认证、用户管理和审计日志接口是否正确集成 +""" + +import sys +import os +import pytest + +# 将项目根目录添加到 sys.path +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../"))) + + +@pytest.mark.parametrize( + "module_name, desc", + [ + ("app.core.encryption", "加密模块"), + ("app.core.security", "安全模块"), + ("app.core.audit", "审计模块"), + ("app.domain.models.role", "角色模型"), + ("app.domain.schemas.user", "用户Schema"), + ("app.domain.schemas.audit", "审计Schema"), + ("app.auth.permissions", "权限控制"), + ("app.api.v1.endpoints.auth", "认证接口"), + ("app.api.v1.endpoints.user_management", "用户管理接口"), + ("app.api.v1.endpoints.audit", "审计日志接口"), + ("app.infra.repositories.user_repository", "用户仓储"), + ("app.infra.repositories.audit_repository", "审计仓储"), + ("app.infra.audit.middleware", "审计中间件"), + ], +) +def test_module_imports(module_name, desc): + """检查关键模块是否可以导入""" + try: + __import__(module_name) + except ImportError as e: + pytest.fail(f"无法导入 {desc} ({module_name}): {e}") + + +def test_router_configuration(): + """检查路由配置""" + try: + from app.api.v1 import router + + # 检查 router 中是否包含新增的路由 + api_router = router.api_router + routes = [r.path for r in api_router.routes if hasattr(r, "path")] + + # 验证基础路径是否存在 + assert any("/auth" in r for r in routes), "缺少认证相关路由 (/auth)" + assert any("/users" in r for r in routes), "缺少用户管理路由 (/users)" + assert any("/audit" in r for r in routes), "缺少审计日志路由 (/audit)" + + except Exception as e: + pytest.fail(f"路由配置检查失败: {e}") + + +def test_main_app_initialization(): + """检查 main.py 配置""" + try: + from app.main import app + + assert app is not None + assert app.title != "" + + # 检查中间件 (简单检查是否存在) + middleware_names = [m.cls.__name__ for m in app.user_middleware] + # 检查是否包含审计中间件或其他关键中间件(根据实际类名修改) + assert "AuditMiddleware" in middleware_names, "缺少审计中间件" + + # 检查路由总数 + assert len(app.routes) > 0 + + except Exception as e: + pytest.fail(f"main.py 配置检查失败: {e}") diff --git a/tests/api/test_leakage_endpoints.py b/tests/api/test_leakage_endpoints.py new file mode 100644 index 0000000..db8ec69 --- /dev/null +++ b/tests/api/test_leakage_endpoints.py @@ -0,0 +1,68 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient +from types import SimpleNamespace + +from app.api.v1.endpoints import leakage as leakage_endpoint + + +def _build_client() -> TestClient: + app = FastAPI() + app.include_router(leakage_endpoint.router, prefix="/api/v1/leakage") + app.dependency_overrides[leakage_endpoint.get_current_keycloak_username] = ( + lambda: "tester" + ) + return TestClient(app) + + +def test_identify_leakage_success(monkeypatch): + def fake_run_leakage_identification(**kwargs): + assert kwargs["network"] == "demo" + assert kwargs["username"] == "tester" + return {"rows": [], "area_count": 0} + + monkeypatch.setattr( + leakage_endpoint, "run_leakage_identification", fake_run_leakage_identification + ) + client = _build_client() + response = client.post( + "/api/v1/leakage/identify/", + json={ + "network": "demo", + "scada_start": "2026-01-01T00:00:00+08:00", + "scada_end": "2026-01-01T01:00:00+08:00", + "scheme_name": "dma_001", + }, + ) + assert response.status_code == 200 + assert response.json()["area_count"] == 0 + + +def test_query_leakage_schemes_success(monkeypatch): + monkeypatch.setattr( + leakage_endpoint, + "list_leakage_identify_schemes", + lambda network, query_date=None: [ + {"scheme_name": "dma_001", "scheme_type": "dma_leak_identification"} + ], + ) + client = _build_client() + response = client.get("/api/v1/leakage/schemes/", params={"network": "demo"}) + assert response.status_code == 200 + assert response.json()[0]["scheme_name"] == "dma_001" + + +def test_query_leakage_scheme_detail_success(monkeypatch): + monkeypatch.setattr( + leakage_endpoint, + "get_leakage_identify_scheme_detail", + lambda network, scheme_name: { + "scheme_name": scheme_name, + "rows": [{"Area": "1", "LeakageFlow_m3_per_s": 0.1}], + }, + ) + client = _build_client() + response = client.get( + "/api/v1/leakage/schemes/dma_001", params={"network": "demo"} + ) + assert response.status_code == 200 + assert response.json()["scheme_name"] == "dma_001" diff --git a/tests/auth/test_encryption.py b/tests/auth/test_encryption.py new file mode 100644 index 0000000..11907dc --- /dev/null +++ b/tests/auth/test_encryption.py @@ -0,0 +1,41 @@ +""" +测试加密功能 +""" + +import os +import sys + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) + + +def test_encryption(): + """测试加密和解密功能""" + from app.core.encryption import Encryptor + + # 生成测试密钥 + key = Encryptor.generate_key() + print(f"✓ 生成密钥: {key}") + + # 创建加密器 + encryptor = Encryptor(key=key.encode()) + + # 测试加密 + test_data = "这是敏感数据 - 数据库密码: password123" + encrypted = encryptor.encrypt(test_data) + print(f"✓ 加密成功: {encrypted[:50]}...") + + # 测试解密 + decrypted = encryptor.decrypt(encrypted) + assert decrypted == test_data, "解密数据不匹配!" + print(f"✓ 解密成功: {decrypted}") + + # 测试空数据 + assert encryptor.encrypt("") == "" + assert encryptor.decrypt("") == "" + print("✓ 空数据处理正确") + + print("\n✅ 所有加密测试通过!") + + +if __name__ == "__main__": + test_encryption() diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..b1c7e7b --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,14 @@ +import pytest +import sys +import os + +# 自动添加项目根目录到路径(处理项目结构) +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + + +def run_this_test(test_file): + """自定义函数:运行单个测试文件(类似pytest)""" + # 提取测试文件名(无扩展名) + test_name = os.path.splitext(os.path.basename(test_file))[0] + # 使用pytest运行(自动处理导入) + pytest.main([test_file, "-v"]) diff --git a/tests/unit/test_burst_location_service.py b/tests/unit/test_burst_location_service.py new file mode 100644 index 0000000..abe38a1 --- /dev/null +++ b/tests/unit/test_burst_location_service.py @@ -0,0 +1,301 @@ +import importlib.util +import sys +import types +from datetime import datetime, timedelta +from pathlib import Path + +import pytest + + +def _load_burst_location_module(): + module_path = ( + Path(__file__).resolve().parents[2] / "app" / "services" / "burst_location.py" + ) + + def ensure_package(name: str) -> types.ModuleType: + module = sys.modules.get(name) + if module is None: + module = types.ModuleType(name) + module.__path__ = [] + sys.modules[name] = module + return module + + for package_name in [ + "app", + "app.algorithms", + "app.infra", + "app.infra.db", + "app.infra.db.timescaledb", + "app.services", + ]: + ensure_package(package_name) + + algorithms_module = types.ModuleType("app.algorithms.burst_location") + algorithms_module.run_burst_location = lambda **kwargs: {} + sys.modules["app.algorithms.burst_location"] = algorithms_module + + internal_queries_module = types.ModuleType( + "app.infra.db.timescaledb.internal_queries" + ) + + class DummyInternalQueries: + @staticmethod + def query_scada_by_ids_timerange(**kwargs): + return {} + + @staticmethod + def query_scheme_simulation_by_ids_timerange(**kwargs): + return {} + + @staticmethod + def query_realtime_simulation_by_ids_timerange(**kwargs): + return {} + + internal_queries_module.InternalQueries = DummyInternalQueries + sys.modules["app.infra.db.timescaledb.internal_queries"] = internal_queries_module + + scheme_management_module = types.ModuleType("app.services.scheme_management") + scheme_management_module.query_burst_location_scheme_detail = lambda *args, **kwargs: {} + scheme_management_module.query_burst_location_schemes = lambda *args, **kwargs: [] + scheme_management_module.scheme_name_exists = lambda *args, **kwargs: False + scheme_management_module.store_scheme_info = lambda *args, **kwargs: None + sys.modules["app.services.scheme_management"] = scheme_management_module + + tjnetwork_module = types.ModuleType("app.services.tjnetwork") + tjnetwork_module.dump_inp = lambda *args, **kwargs: None + tjnetwork_module.get_all_scada_info = lambda *args, **kwargs: [] + sys.modules["app.services.tjnetwork"] = tjnetwork_module + + module_name = "tests_burst_location_under_test" + spec = importlib.util.spec_from_file_location(module_name, module_path) + module = importlib.util.module_from_spec(spec) + assert spec and spec.loader + spec.loader.exec_module(module) + return module + + +def test_run_burst_location_uses_single_timerange_with_burst_source_split(monkeypatch, tmp_path): + module = _load_burst_location_module() + captured = {} + scheme_calls = [] + realtime_calls = [] + + monkeypatch.setattr( + module, + "get_all_scada_info", + lambda network: [ + { + "type": "pressure", + "associated_element_id": "J1", + "api_query_id": "pressure-query", + }, + { + "type": "pipe_flow", + "associated_element_id": "P1", + "api_query_id": "pipe-flow-query", + }, + { + "type": "demand", + "associated_element_id": "J2", + "api_query_id": "demand-query", + }, + ], + ) + monkeypatch.setattr(module, "_prepare_burst_inp", lambda network: str(tmp_path / "fake.inp")) + + def fake_run_burst_location(**kwargs): + captured.update(kwargs) + return { + "located_pipe": "Pipe-001", + "simulation_times": 3, + "similarity_mode": "combined", + } + + monkeypatch.setattr(module, "run_burst_location", fake_run_burst_location) + + def _build_series(start_time: str, values: list[float]) -> list[dict]: + base_time = datetime.fromisoformat(start_time) + return [ + { + "time": (base_time + timedelta(minutes=15 * index)).isoformat(), + "value": value, + } + for index, value in enumerate(values) + ] + + def fake_scheme_query(**kwargs): + scheme_calls.append(kwargs) + if kwargs["element_type"] == "node" and kwargs["field"] == "pressure": + start_hour = datetime.fromisoformat(kwargs["start_time"]).hour + values = [12.0, 14.0, 16.0, 18.0] if start_hour == 8 else [8.0, 10.0, 12.0, 14.0] + return {"J1": _build_series(kwargs["start_time"], values)} + if kwargs["element_type"] == "link" and kwargs["field"] == "flow": + start_hour = datetime.fromisoformat(kwargs["start_time"]).hour + values = [5.0, 7.0, 9.0, 11.0] if start_hour == 8 else [2.0, 4.0, 6.0, 8.0] + return {"P1": _build_series(kwargs["start_time"], values)} + if kwargs["element_type"] == "node" and kwargs["field"] == "actual_demand": + start_hour = datetime.fromisoformat(kwargs["start_time"]).hour + values = [3.0, 5.0, 7.0, 9.0] if start_hour == 8 else [1.0, 3.0, 5.0, 7.0] + return {"J2": _build_series(kwargs["start_time"], values)} + raise AssertionError(f"Unexpected scheme query: {kwargs}") + + def fake_realtime_query(**kwargs): + realtime_calls.append(kwargs) + if kwargs["element_type"] == "node" and kwargs["field"] == "pressure": + return {"J1": _build_series(kwargs["start_time"], [8.0, 10.0, 12.0, 14.0])} + if kwargs["element_type"] == "link" and kwargs["field"] == "flow": + return {"P1": _build_series(kwargs["start_time"], [2.0, 4.0, 6.0, 8.0])} + if kwargs["element_type"] == "node" and kwargs["field"] == "actual_demand": + return {"J2": _build_series(kwargs["start_time"], [1.0, 3.0, 5.0, 7.0])} + raise AssertionError(f"Unexpected realtime query: {kwargs}") + + monkeypatch.setattr( + module.InternalQueries, + "query_scheme_simulation_by_ids_timerange", + staticmethod(fake_scheme_query), + ) + monkeypatch.setattr( + module.InternalQueries, + "query_realtime_simulation_by_ids_timerange", + staticmethod(fake_realtime_query), + ) + + result = module.run_burst_location_by_network( + network="tjwater", + username="testuser", + data_source="simulation", + simulation_scheme_name="BurstSchemeA", + simulation_scheme_type="burst_analysis", + burst_leakage=10.0, + scada_burst_start=datetime(2025, 1, 1, 8, 0, 0), + scada_burst_end=datetime(2025, 1, 1, 9, 0, 0), + use_scada_flow=True, + ) + + assert result["observed_source"] == "simulation_scheme_burst_realtime_normal_timerange" + assert result["simulation_scheme"] == { + "name": "BurstSchemeA", + "type": "burst_analysis", + } + assert result["pressure_samples"] == {"burst": 4, "normal": 4} + assert result["flow_samples"] == {"burst": 4, "normal": 4} + assert list(captured["burst_pressure"].index) == ["J1"] + assert captured["burst_pressure"]["J1"] == pytest.approx(15.0) + assert captured["normal_pressure"]["J1"] == pytest.approx(11.0) + assert captured["burst_flow"]["J2"] == pytest.approx(6.0) + assert captured["burst_flow"]["P1"] == pytest.approx(8.0) + assert captured["normal_flow"]["J2"] == pytest.approx(4.0) + assert captured["normal_flow"]["P1"] == pytest.approx(5.0) + assert all(call["scheme_name"] == "BurstSchemeA" for call in scheme_calls) + assert len(scheme_calls) == 3 + assert any(call["element_type"] == "node" and call["field"] == "pressure" for call in scheme_calls) + assert any(call["element_type"] == "link" and call["field"] == "flow" for call in scheme_calls) + assert any(call["element_type"] == "node" and call["field"] == "actual_demand" for call in scheme_calls) + assert len(realtime_calls) == 3 + assert all(datetime.fromisoformat(call["start_time"]).hour == 8 for call in realtime_calls) + assert all(datetime.fromisoformat(call["end_time"]).hour == 9 for call in realtime_calls) + assert any(call["element_type"] == "node" and call["field"] == "pressure" for call in realtime_calls) + assert any(call["element_type"] == "link" and call["field"] == "flow" for call in realtime_calls) + assert any(call["element_type"] == "node" and call["field"] == "actual_demand" for call in realtime_calls) + assert result["scada_window"] == { + "burst_start": "2025-01-01T08:00:00", + "burst_end": "2025-01-01T09:00:00", + } + + +def test_run_burst_location_requires_simulation_scheme_name(monkeypatch, tmp_path): + module = _load_burst_location_module() + monkeypatch.setattr( + module, + "get_all_scada_info", + lambda network: [ + { + "type": "pressure", + "associated_element_id": "J1", + "api_query_id": "pressure-query", + } + ], + ) + monkeypatch.setattr(module, "_prepare_burst_inp", lambda network: str(tmp_path / "fake.inp")) + monkeypatch.setattr(module, "run_burst_location", lambda **kwargs: {}) + + with pytest.raises(ValueError, match="simulation_scheme_name"): + module.run_burst_location_by_network( + network="tjwater", + username="testuser", + data_source="simulation", + burst_leakage=1.0, + scada_burst_start=datetime(2025, 1, 1, 8, 0, 0), + scada_burst_end=datetime(2025, 1, 1, 9, 0, 0), + ) + + +def test_run_burst_location_monitoring_uses_scada_for_burst_and_realtime_for_normal( + monkeypatch, tmp_path +): + module = _load_burst_location_module() + captured = {} + scada_calls = [] + realtime_calls = [] + + monkeypatch.setattr( + module, + "get_all_scada_info", + lambda network: [ + { + "type": "pressure", + "associated_element_id": "J1", + "api_query_id": "pressure-query", + } + ], + ) + monkeypatch.setattr(module, "_prepare_burst_inp", lambda network: str(tmp_path / "fake.inp")) + monkeypatch.setattr( + module, + "run_burst_location", + lambda **kwargs: captured.update(kwargs) or {"located_pipe": "Pipe-001"}, + ) + + def fake_scada_query(**kwargs): + scada_calls.append(kwargs) + return { + "pressure-query": [ + {"time": kwargs["start_time"], "value": 20.0}, + {"time": kwargs["end_time"], "value": 22.0}, + ] + } + + def fake_realtime_query(**kwargs): + realtime_calls.append(kwargs) + return { + "J1": [ + {"time": kwargs["start_time"], "value": 10.0}, + {"time": kwargs["end_time"], "value": 12.0}, + ] + } + + monkeypatch.setattr( + module.InternalQueries, + "query_scada_by_ids_timerange", + staticmethod(fake_scada_query), + ) + monkeypatch.setattr( + module.InternalQueries, + "query_realtime_simulation_by_ids_timerange", + staticmethod(fake_realtime_query), + ) + + result = module.run_burst_location_by_network( + network="tjwater", + username="testuser", + data_source="monitoring", + burst_leakage=1.0, + scada_burst_start=datetime(2025, 1, 1, 8, 0, 0), + scada_burst_end=datetime(2025, 1, 1, 9, 0, 0), + ) + + assert result["observed_source"] == "scada_burst_realtime_normal_timerange" + assert len(scada_calls) == 1 + assert len(realtime_calls) == 1 + assert captured["burst_pressure"]["J1"] == pytest.approx(21.0) + assert captured["normal_pressure"]["J1"] == pytest.approx(11.0) diff --git a/tests/unit/test_metadata_repository_dsn_decrypt.py b/tests/unit/test_metadata_repository_dsn_decrypt.py new file mode 100644 index 0000000..02796e1 --- /dev/null +++ b/tests/unit/test_metadata_repository_dsn_decrypt.py @@ -0,0 +1,119 @@ +import asyncio +from types import SimpleNamespace +from unittest.mock import AsyncMock +from uuid import uuid4 + +import pytest +from cryptography.fernet import InvalidToken + +from app.infra.repositories.metadata_repository import MetadataRepository + + +class _DummyResult: + def __init__(self, record): + self._record = record + + def scalar_one_or_none(self): + return self._record + + +class _DummyEncryptor: + def __init__(self, decrypted=None, raise_invalid_token=False): + self._decrypted = decrypted + self._raise_invalid_token = raise_invalid_token + self.encrypted_values = [] + + def decrypt(self, _value): + if self._raise_invalid_token: + raise InvalidToken() + return self._decrypted + +def _build_record(dsn_encrypted: str): + return SimpleNamespace( + project_id=uuid4(), + db_role="biz_data", + db_type="postgresql", + dsn_encrypted=dsn_encrypted, + pool_min_size=1, + pool_max_size=5, + ) + + +def test_invalid_token_with_plaintext_dsn_value_raises_clear_error(monkeypatch): + record = _build_record("postgresql://user:p@ss@localhost:5432/db") + session = SimpleNamespace( + execute=None, + commit=None, + ) + session.execute = AsyncMock(return_value=_DummyResult(record)) + session.commit = AsyncMock() + encryptor = _DummyEncryptor(raise_invalid_token=True) + repo = MetadataRepository(session) + + monkeypatch.setattr( + "app.infra.repositories.metadata_repository.is_database_encryption_configured", + lambda: True, + ) + monkeypatch.setattr( + "app.infra.repositories.metadata_repository.get_database_encryptor", + lambda: encryptor, + ) + + with pytest.raises( + ValueError, + match="DATABASE_ENCRYPTION_KEY mismatch or invalid dsn_encrypted value", + ): + asyncio.run(repo.get_project_db_routing(record.project_id, "biz_data")) + session.commit.assert_not_awaited() + + +def test_invalid_token_with_non_dsn_value_raises_clear_error(monkeypatch): + record = _build_record("gAAAAABinvalidciphertext") + session = SimpleNamespace( + execute=None, + commit=None, + ) + session.execute = AsyncMock(return_value=_DummyResult(record)) + session.commit = AsyncMock() + repo = MetadataRepository(session) + + monkeypatch.setattr( + "app.infra.repositories.metadata_repository.is_database_encryption_configured", + lambda: True, + ) + monkeypatch.setattr( + "app.infra.repositories.metadata_repository.get_database_encryptor", + lambda: _DummyEncryptor(raise_invalid_token=True), + ) + + with pytest.raises( + ValueError, + match="DATABASE_ENCRYPTION_KEY mismatch or invalid dsn_encrypted value", + ): + asyncio.run(repo.get_project_db_routing(record.project_id, "biz_data")) + session.commit.assert_not_awaited() + + +def test_encrypted_dsn_decrypts_without_migration(monkeypatch): + record = _build_record("encrypted-value") + session = SimpleNamespace( + execute=None, + commit=None, + ) + session.execute = AsyncMock(return_value=_DummyResult(record)) + session.commit = AsyncMock() + repo = MetadataRepository(session) + + monkeypatch.setattr( + "app.infra.repositories.metadata_repository.is_database_encryption_configured", + lambda: True, + ) + monkeypatch.setattr( + "app.infra.repositories.metadata_repository.get_database_encryptor", + lambda: _DummyEncryptor(decrypted="postgresql://u:p@ss@host/db"), + ) + + routing = asyncio.run(repo.get_project_db_routing(record.project_id, "biz_data")) + + assert routing.dsn == "postgresql://u:p%40ss@host/db" + session.commit.assert_not_awaited() diff --git a/tests/unit/test_pipeline_health_analyzer.py b/tests/unit/test_pipeline_health_analyzer.py new file mode 100644 index 0000000..6342295 --- /dev/null +++ b/tests/unit/test_pipeline_health_analyzer.py @@ -0,0 +1,64 @@ +""" +tests.unit.test_pipeline_health_analyzer 的 Docstring +""" + + +def test_pipeline_health_analyzer(): + from app.algorithms.health.analyzer import PipelineHealthAnalyzer + + # 初始化分析器,假设模型文件路径为'models/rsf_model.joblib' + analyzer = PipelineHealthAnalyzer() + # 创建示例输入数据(9个样本) + import pandas as pd + import time + + base_data = pd.DataFrame( + { + "Material": [7, 11, 7, 7, 7, 7, 7, 7, 7], + "Diameter": [6, 6, 3, 2, 3, 3, 2, 2, 2], + "Flow Velocity": [0.55, 0.32, 0.25, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4], + "Pressure": [0.15, 0.15, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2], + } + ) + + # 复制生成10万样本 + num_samples = 100 + repetitions = num_samples // len(base_data) + 1 + sample_data = pd.concat([base_data] * repetitions, ignore_index=True).head( + num_samples + ) + + print(f"生成了 {len(sample_data)} 个样本") + + # 记录开始时间 + start_time = time.time() + + # 进行生存预测 + survival_functions = analyzer.predict_survival(sample_data) + + # 记录结束时间 + end_time = time.time() + elapsed_time = end_time - start_time + print(f"预测耗时: {elapsed_time:.2f} 秒") + + # 打印预测结果示例 + print(f"预测了 {len(survival_functions)} 个生存函数") + for i, sf in enumerate(survival_functions): + print( + f"样本 {i+1}: 时间点数量={len(sf.x)}, 生存概率范围={sf.y.min():.3f} - {sf.y.max():.3f} {sf}" + ) + + # 验证返回结果类型 + assert isinstance(survival_functions, list), "返回值应为列表" + assert all( + hasattr(sf, "x") and hasattr(sf, "y") for sf in survival_functions + ), "每个生存函数应包含x和y属性" + + # 可选:测试绘图功能(不显示图表) + analyzer.plot_survival(survival_functions, show_plot=False) + + +if __name__ == "__main__": + import conftest + + conftest.run_this_test(__file__) # 自定义运行,类似示例