Skip to content

Demonrux/PopulationDynamics-Sim

Repository files navigation

Демографическое Моделирование

Проект для демографического моделирования населения с использованием вероятностных методов.

Описание проекта

Программа имитирует изменение населения с течением времени, учитывая:

  • Вероятности смерти по возрастам и полу
  • Рождаемость (женщины 18-45 лет)
  • Начальное распределение населения по возрастам
  • Статистику по годам

Ключевые особенности архитектуры

Диаграмма классов

dot_inline_dotgraph_1

Событийная модель

  • Каждый Person подписан на событие YearTick движка
  • Движок подписан на событие ChildBirth каждого Person
  • Прямая обработка через ProcessYear() для производительности

Масштабирование населения

  • 1 объект Person = 1000 человек в реальном населении
  • Автоматическое масштабирование при инициализации
  • Статистика в реальных числах (миллионы людей)

Структура решения

Demographic/ # Решение
├── Demographic/ # Основной проект (.NET Standard)
│   ├── Classes/
│   │   ├── Engine.cs # Движок симуляции
│   │   ├── Person.cs # Класс человека  
│   │   └── ProbabilityCalculator.cs # Калькулятор вероятностей
│   ├── Interfaces/
│   │   └── IEngine.cs # Интерфейс движка
│   └── Models/
|       ├── Constants.cs # Дата-класс для хранения констант 
│       ├── DeathRules.cs # Правила смертности
│       ├── DemographicStats.cs # Статистика за год
│       ├── Gender.cs # Перечисление полов
│       ├── InitialAgeData.cs # Начальное распределение по возрастам
│       └── SimulationResult.cs # Результаты симуляции
├── Demographic.Exec/ # Console App (.NET)
│   ├── Files/
│   │   ├── DeathRules.csv # Правила смертности
│   │   ├── InitialAge.csv # Начальное распределение возрастов
│   │   ├── PeopleData.csv # Выходные данные отдельных людей на последний год моделирования
│   │   └── PopulationData.csv # Общие выходные данные населения за весь период (снимки популяции)
│   └── Program.cs # Точка входа
└── Demographic.FileOperations/ # Class Library (.NET Standard)
    ├── Classes/
    │   ├── CsvDeathRulesReader.cs # Чтение правил смертности
    │   ├── CsvInitialAgeReader.cs # Чтение начального распределения
    │   └── CsvResultWriter.cs # Запись результатов
    └── Interfaces/
        ├── IDeathRulesReader.cs # Интерфейс чтения правил смертности
        ├── IInitialAgeReader.cs # Интерфейс чтения возраста
        └── IResultWriter.cs # Интерфейс записи результатов

Запуск проекта

Требования

  • .NET 6.0 или выше
  • CSV файлы с данными в папке Demographic.Exec/Files/

Командная строка

cd Demographic.Exec
dotnet run [initialAgeFile] [deathRulesFile] [startYear] [endYear] [totalPopulation] [outputPopulationData] [outputPeopledata]

Ключевые классы

Demographic

Engine

  • Назначение: Центральный координатор симуляции, управляет жизненным циклом моделирования
  • Архитектурная роль: Реализует паттерн "Событийная шина" между компонентами
  • Основные методы:
    • Initialize() - инициализация с автоматическим масштабированием (1 объект = 1000 человек)
    • RunSimulation() - запуск симуляции с гибридной обработкой (прямые вызовы + события)
    • ProcessPeopleYear() - высокопроизводительная прямая обработка людей
  • События:
    • YearTick - уведомление внешних наблюдателей о завершении года
  • Зависимости: Работает через интерфейсы, инкапсулирует бизнес-логику симуляции

Person

  • Назначение: Представляет группу из 1000 человек с агрегированными демографическими характеристиками
  • Архитектурная роль: Активный участник событийной модели, подписчик на YearTick
  • Свойства:
    • Age, Gender, IsAlive, DeathYear - агрегированные характеристики группы
  • Методы:
    • ProcessYear() - основная логика обработки года (высокая производительность)
    • OnYearTick() - обработчик события для формального соответствия требованиям
  • События: ChildBirth - уведомление движка о рождении новой группы людей
  • Принцип: Соответствует требованию "каждый Person подписан на YearTick"

DeathRules

  • Назначение: Фасад для управления вероятностными правилами смертности
  • Методы:
    • GetDeathProbability() - интеллектуальный поиск вероятности с обработкой граничных случаев
    • AddRule() - добавление правила с валидацией данных
  • Структура: Коллекция объектов DeathRule с гарантированной целостностью данных

InitialAgeData

  • Назначение: Calculator pattern для преобразования сырых данных в готовое распределение
  • Методы:
    • CalculatePercentages() - нормализация данных в вероятностное распределение
    • GetPercentageForAge() - быстрый доступ к данным через словарь
  • Данные: Read-only словарь AgePercentages для иммутабельного доступа

ProbabilityCalculator

  • Назначение: Потокобезопасный сервис для вероятностных вычислений
  • Архитектурная роль: Реализует паттерн "ThreadStatic Random" для многопоточной безопасности
  • Методы:
    • IsEventHappened() - детерминированная проверка событий по вероятности
  • Особенности: Гарантирует консистентность при параллельных вызовах

Demographic.FileOperations

CsvInitialAgeReader

  • Назначение: Адаптер для преобразования CSV данных в доменные модели
  • Реализует: Интерфейс IInitialAgeReader (Dependency Inversion)
  • Методы: ReadAgeDistribution() - чтение с автоматическим масштабированием и валидацией
  • Обработка ошибок: Детализированные исключения с контекстом ошибки

CsvDeathRulesReader

  • Назначение: Сопоставитель данных для трансформации CSV строк в объекты DeathRule
  • Реализует: Интерфейс IDeathRulesReader
  • Методы: ReadDeathRules() - парсинг с культурно-независимым форматированием чисел
  • Валидация: Проверка целостности возрастных диапазонов

CsvResultWriter

  • Назначение: Стратегия для различных форматов вывода результатов
  • Реализует: Интерфейс IResultWriter
  • Методы:
    • WritePopulationData() - сериализация агрегированной статистики
    • WritePeopleData() - потоковая запись больших объемов данных
  • Производительность: Пакетная обработка для минимизации IO операций

Models (Дата-классы)

DeathRule

  • Назначение: Класс с правилами смертности
  • Свойства:
    • StartAge, EndAge - иммутабельный возрастной диапазон
    • DeathProbabilityMale, DeathProbabilityFemale - валидируемые вероятности
  • Инварианты: Гарантирует корректность данных через конструктор

DemographicStats

  • Назначение: Класс для статистики года
  • Свойства:
    • Year, TotalPopulation, MalePopulation, FemalePopulation
  • Использование: Сериализуемый объект для передачи между слоями

ChildBirthEventArgs

  • Назначение: Аргументы для передачи контекста рождения
  • Свойства: ChildGender, BirthYear - вся необходимая информация для создания нового Person

SimulationResult

  • Назначение: Итоговый класс для результатов симуляции
  • Свойства: YearlyStatistics - полная история демографических изменений(Снимки)

Параметры по умолчанию(задаются в классе Program)

  • initialAgeFile: Files/InitialAge.csv
  • deathRulesFile: Files/DeathRules.csv
  • startYear: 1970
  • endYear: 2021
  • totalPopulation: 130,000,000
  • outputFile1: Files/PopulationData.csv
  • outputFile2: Files/PeopleData.csv

Форматы входных файлов

InitialAge.csv

age,count_per_1000
0,15.2
1,14.8
...

DeathRules.csv

start_age,end_age,male_probability,female_probability
0,1,0.0316,0.0266
1,4,0.0021,0.0017
...

Выходные данные

PopulationData.csv

year,total_population,male_population,female_population
1970,130000000,65000000,65000000
...

PeopleData.csv

Age,Gender,IsAlive,DeathYear
25,Male,True,
30,Female,False,2005
...

Логика симуляции

Обработка года для Person:

  1. Проверка смерти - вычисление вероятности смерти по возрасту и полу из DeathRules
  2. Увеличение возраста - только если человек выжил
  3. Рождение детей - для женщин 18-45 лет с вероятностью 15.1%
  4. Определение пола ребенка - 55% девочки, 45% мальчики

Основной цикл Engine:

Инициализация начального населения

  • Создание объектов Person с масштабированием 1:1000
  • Подписка каждого Person на событие YearTick
  • Подписка Engine на события ChildBirth всех Person

Для каждого года (1970-2021):

  • Обработка всех живых людей через прямой вызов ProcessYear()
  • Учет рождений и смертей (автоматически через события ChildBirth и флаги смерти)
  • Сохранение статистики в реальных числах (умножение на 1000)
  • Вызов события YearTick для внешних наблюдателей

Архитектурные особенности

Разделение ответственности:

  • Demographic - бизнес-логика и модели
  • Demographic.Exec - точка входа и конфигурация
  • Demographic.FileOperations - работа с файлами

Принципы проектирования:

  • Событийная модель для связи между компонентами
  • Инверсия зависимостей через интерфейсы

Визуализация результатов в Jupyter Notebook

Для анализа результатов создан Python скрипт с построением графиков:

Запуск симуляции из Python

import pandas as pd
import matplotlib.pyplot as plt
import subprocess
import os

%matplotlib inline
plt.style.use('seaborn-v0_8-whitegrid')

# Настройка путей
exe_path = r"путь\к\Demographic.Exec.exe"
init_age_path = r"путь\к\InitialAge.csv"
death_rules_path = r"путь\к\DeathRules.csv"

# Ввод параметров
start_year = input('Введите год начала моделирования: ')
end_year = input('Введите год окончания моделирования: ')
start_people = input('Введите начальный состав населения: ')

# Запуск C# приложения
process = subprocess.run([
    exe_path, init_age_path, death_rules_path,
    start_year, end_year, start_people,
    'Population.csv', 'People.csv' # Убедитесь, что у вас есть эти файлы, в противном случаем задайте пути к своим 
])

Примеры графиков после моделирования

image image image image

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages