├── requirements.txt ├── .gitignore ├── code ├── io_tree_binary.h ├── io_save_binary.h ├── io_tree_hdf5.h ├── git_version.h.in ├── io_save_hdf5.h ├── config.h ├── core_allvars.h ├── core_simulation.h ├── io_tree.h ├── util_parameters.h ├── util_version.h ├── util_memory.h ├── constants.h ├── util_numeric.c ├── doc_standards.md ├── globals.h ├── util_integration.h ├── core_allvars.c ├── model_reincorporation.c ├── util_numeric.h ├── util_error.h ├── io_util.h ├── core_proto.h ├── util_integration.c ├── error_handling_guidelines.md ├── io_tree_binary.c ├── core_simulation_state.c └── model_disk_instability.c ├── output └── sage-plot │ ├── setup.py │ ├── test_plotting.sh │ └── figures │ ├── baryonic_tully_fisher.py │ ├── halo_mass_function.py │ ├── specific_sfr.py │ ├── black_hole_bulge_relation.py │ ├── baryonic_mass_function.py │ ├── spatial_distribution.py │ ├── gas_fraction.py │ ├── mass_reservoir_scatter.py │ ├── bulge_mass_fraction.py │ ├── velocity_distribution.py │ ├── metallicity.py │ └── __init__.py ├── LICENSE.txt ├── Makefile ├── input └── millennium.par ├── extra └── CoolFunctions │ ├── ABOUT.txt │ ├── stripped_m+05.cie │ ├── stripped_m-00.cie │ ├── stripped_m-05.cie │ ├── stripped_m-10.cie │ ├── stripped_m-15.cie │ ├── stripped_m-20.cie │ ├── stripped_m-30.cie │ └── stripped_mzero.cie └── beautify.sh /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.20.0 2 | matplotlib>=3.0.0 3 | tqdm>=4.0.0 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | sage 2 | input/data 3 | output/results 4 | ignore/ 5 | *.o 6 | *.*~ 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | code/git_version.h 11 | 12 | # Claude Code session data 13 | .claude/ 14 | 15 | # Python virtual environment 16 | sage_venv/ -------------------------------------------------------------------------------- /code/io_tree_binary.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_BINARY_H 2 | #define TREE_BINARY_H 3 | 4 | // Proto-Types // 5 | 6 | void load_tree_table_binary(int32_t filenr); 7 | void load_tree_binary(int32_t filenr, int32_t treenr); 8 | void close_binary_file(void); 9 | #endif 10 | -------------------------------------------------------------------------------- /code/io_save_binary.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_SAVE_BINARY_H 2 | #define IO_SAVE_BINARY_H 3 | 4 | /* Functions for binary file saving */ 5 | void save_galaxies(int filenr, int tree); 6 | void finalize_galaxy_file(int filenr); 7 | void close_galaxy_files(void); 8 | 9 | #endif /* IO_SAVE_BINARY_H */ 10 | -------------------------------------------------------------------------------- /code/io_tree_hdf5.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_HDF5_H 2 | #define TREE_HDF5_H 3 | 4 | #ifdef HDF5 5 | #include 6 | 7 | // Proto-Types // 8 | 9 | void load_tree_table_hdf5(int filenr); 10 | void load_tree_hdf5(int32_t filenr, int32_t treenr); 11 | void close_hdf5_file(void); 12 | 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /code/git_version.h.in: -------------------------------------------------------------------------------- 1 | /** 2 | * @file git_version.h 3 | * @brief Auto-generated file containing Git version information 4 | * 5 | * This file is automatically generated during the build process. 6 | * DO NOT EDIT MANUALLY. 7 | */ 8 | 9 | #ifndef GIT_VERSION_H 10 | #define GIT_VERSION_H 11 | 12 | #define GIT_COMMIT_HASH "@GIT_COMMIT_HASH@" 13 | #define GIT_BRANCH_NAME "@GIT_BRANCH_NAME@" 14 | 15 | #endif /* GIT_VERSION_H */ 16 | -------------------------------------------------------------------------------- /code/io_save_hdf5.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_SAVE_HDF5_H 2 | #define IO_SAVE_HDF5_H 3 | 4 | #include "config.h" 5 | #include "globals.h" 6 | #include "types.h" 7 | 8 | extern void calc_hdf5_props(void); 9 | extern void write_hdf5_galaxy(struct GALAXY_OUTPUT *galaxy, int n, int filenr); 10 | extern void write_hdf5_attrs(int n, int filenr); 11 | extern void free_hdf5_ids(void); 12 | extern void write_master_file(void); 13 | extern void prep_hdf5_file(char *fname); 14 | 15 | #endif /* #ifndef IO_SAVE_HDF5_H */ 16 | -------------------------------------------------------------------------------- /code/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include "types.h" 5 | #include "util_error.h" 6 | 7 | /* HDF5 configuration */ 8 | #ifdef HDF5 9 | #include 10 | #define MODELNAME "SAGE" 11 | #endif 12 | 13 | /* Legacy ABORT macro - redirects to new FATAL_ERROR macro for backward 14 | * compatibility */ 15 | #define ABORT(sigterm) FATAL_ERROR("Program aborted with exit code %d", sigterm) 16 | 17 | /* Global configuration structure - replaces individual globals */ 18 | extern struct SageConfig SageConfig; 19 | 20 | #endif /* #ifndef CONFIG_H */ 21 | -------------------------------------------------------------------------------- /code/core_allvars.h: -------------------------------------------------------------------------------- 1 | #ifndef ALLVARS_H 2 | #define ALLVARS_H 3 | 4 | /* 5 | * This is a transitional header that includes the refactored headers 6 | * for backward compatibility. In future updates, code should directly 7 | * include the specific headers needed rather than core_allvars.h. 8 | * 9 | * IMPORTANT NOTE: 10 | * When modifying global parameters that have been moved to the SageConfig 11 | * structure, you must ensure that both the global variable and the structure 12 | * field are kept in sync. Some functions still use global variables and some 13 | * use the SageConfig structure. 14 | */ 15 | 16 | #include "config.h" 17 | #include "constants.h" 18 | #include "globals.h" 19 | #include "types.h" 20 | 21 | #endif /* #ifndef ALLVARS_H */ 22 | -------------------------------------------------------------------------------- /code/core_simulation.h: -------------------------------------------------------------------------------- 1 | 2 | struct halo_data { 3 | // merger tree pointers 4 | int Descendant; 5 | int FirstProgenitor; 6 | int NextProgenitor; 7 | int FirstHaloInFOFgroup; 8 | int NextHaloInFOFgroup; 9 | 10 | // properties of halo 11 | int Len; 12 | float M_Mean200, Mvir, M_TopHat; // for Millennium, Mvir=M_Crit200 13 | float Pos[3]; 14 | float Vel[3]; 15 | float VelDisp; 16 | float Vmax; 17 | float Spin[3]; 18 | long long MostBoundID; // for LHaloTrees, this is the ID of the most bound 19 | // particle; for other mergertree codes, let this 20 | // contain a unique haloid 21 | 22 | // original position in simulation tree files 23 | int SnapNum; 24 | int FileNr; 25 | int SubhaloIndex; 26 | float SubHalfMass; 27 | } *Halo; 28 | -------------------------------------------------------------------------------- /code/io_tree.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_TREE_H 2 | #define IO_TREE_H 3 | 4 | /* Functions for tree I/O operations */ 5 | void load_tree(int filenr, int treenr, enum Valid_TreeTypes TreeType); 6 | void load_tree_table(int filenr, enum Valid_TreeTypes my_TreeType); 7 | void free_tree_table(enum Valid_TreeTypes my_TreeType); 8 | void free_galaxies_and_tree(void); 9 | 10 | /* I/O wrapper functions with endianness handling and buffering */ 11 | void set_file_endianness(int endianness); 12 | int get_file_endianness(void); 13 | void init_io_buffering(void); 14 | void cleanup_io_buffering(void); 15 | size_t myfread(void *ptr, size_t size, size_t nmemb, FILE *stream); 16 | size_t myfwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); 17 | int myfseek(FILE *stream, long offset, int whence); 18 | 19 | #endif /* IO_TREE_H */ 20 | -------------------------------------------------------------------------------- /output/sage-plot/setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Setup script for the SAGE Plotting Tool package. 5 | 6 | This file defines the package metadata, dependencies, and entry points 7 | for the SAGE Plotting Tool, which provides a centralized system for 8 | generating plots from SAGE galaxy formation model outputs. 9 | """ 10 | 11 | from setuptools import find_packages, setup 12 | 13 | setup( 14 | name="sage-plot", 15 | version="0.1.0", 16 | description="Centralized plotting tool for the SAGE galaxy formation model", 17 | author="SAGE Team", 18 | packages=find_packages(), 19 | entry_points={ 20 | "console_scripts": [ 21 | "sage-plot=sage_plot:main", 22 | ], 23 | }, 24 | install_requires=[ 25 | "numpy", 26 | "matplotlib", 27 | "tqdm", 28 | ], 29 | python_requires=">=3.6", 30 | ) 31 | -------------------------------------------------------------------------------- /code/util_parameters.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAMETER_TABLE_H 2 | #define PARAMETER_TABLE_H 3 | 4 | #include "constants.h" 5 | #include "types.h" 6 | 7 | // Parameter definition structure 8 | typedef struct { 9 | char name[MAX_STRING_LEN]; // Parameter name/tag 10 | char description[MAX_STRING_LEN]; // Description for documentation 11 | int type; // Parameter type (using existing INT, DOUBLE, STRING) 12 | void *address; // Where to store the value 13 | int required; // Whether parameter is required (1) or optional (0) 14 | 15 | // Simple validation for numeric types (ignored for strings) 16 | double min_value; // Minimum allowed value (for numeric types) 17 | double max_value; // Maximum allowed value (for numeric types, 0 = no maximum) 18 | } ParameterDefinition; 19 | 20 | // Function declarations 21 | extern int get_parameter_table_size(void); 22 | extern ParameterDefinition *get_parameter_table(void); 23 | extern int is_parameter_valid(ParameterDefinition *param, void *value); 24 | extern const char *get_parameter_type_string(int type); 25 | 26 | #endif /* #ifndef PARAMETER_TABLE_H */ 27 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 darrencroton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /code/util_version.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file util_version.h 3 | * @brief Functionality for tracking SAGE version information 4 | * 5 | * This file provides function declarations for generating and saving version 6 | * and runtime information to a metadata file in the SAGE output directory. 7 | * This helps with reproducibility by ensuring that output data can always 8 | * be traced back to the exact code version that produced it. 9 | */ 10 | 11 | #ifndef UTIL_VERSION_H 12 | #define UTIL_VERSION_H 13 | 14 | /** 15 | * @brief Creates a version metadata file in the specified output directory 16 | * 17 | * @param output_dir Path to the output directory 18 | * @param parameter_file Path to the parameter file used for this run 19 | * 20 | * This function creates a JSON metadata file in the output directory 21 | * containing information about the SAGE version, build environment, 22 | * git commit details, runtime parameters, and system information. 23 | * 24 | * If git information cannot be retrieved, those fields will be marked 25 | * as unavailable in the output. 26 | * 27 | * @return 0 on success, non-zero on error 28 | */ 29 | int create_version_metadata(const char *output_dir, const char *parameter_file); 30 | 31 | #endif /* UTIL_VERSION_H */ 32 | -------------------------------------------------------------------------------- /code/util_memory.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_MEMORY_H 2 | #define UTIL_MEMORY_H 3 | 4 | #include 5 | 6 | /* Memory categories for component-level tracking */ 7 | typedef enum { 8 | MEM_UNKNOWN = 0, 9 | MEM_GALAXIES, 10 | MEM_HALOS, 11 | MEM_TREES, 12 | MEM_IO, 13 | MEM_UTILITY, 14 | MEM_MAX_CATEGORY /* For bounds checking */ 15 | } MemoryCategory; 16 | 17 | /* Memory reporting levels */ 18 | #define MEMORY_REPORT_NONE 0 19 | #define MEMORY_REPORT_MINIMAL 1 20 | #define MEMORY_REPORT_DETAILED 2 21 | 22 | /* Configuration */ 23 | #ifndef DEFAULT_MAX_MEMORY_BLOCKS 24 | #define DEFAULT_MAX_MEMORY_BLOCKS 1024 /* Increased from 256 */ 25 | #endif 26 | 27 | /* Memory allocation utilities */ 28 | void init_memory_system(unsigned long max_blocks); 29 | void *mymalloc(size_t size); 30 | void *mymalloc_cat(size_t size, MemoryCategory category); 31 | void *myrealloc(void *ptr, size_t size); 32 | void *myrealloc_cat(void *ptr, size_t size, MemoryCategory category); 33 | void myfree(void *ptr); 34 | 35 | /* Memory reporting and debugging */ 36 | void set_memory_reporting(int level); 37 | void print_allocated(void); 38 | void print_allocated_by_category(void); 39 | void print_memory_brief(void); 40 | void check_memory_leaks(void); 41 | int validate_memory_block(void *ptr); 42 | int validate_all_memory(void); 43 | void cleanup_memory_system(void); 44 | 45 | #endif /* UTIL_MEMORY_H */ 46 | -------------------------------------------------------------------------------- /output/sage-plot/test_plotting.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Simple script to test the sage-plot.py functionality 4 | # This script assumes you're in the SAGE root directory 5 | 6 | # Find your parameter file 7 | if [ -f "input/millennium.par" ]; then 8 | PARAM_FILE="input/millennium.par" 9 | echo "Using millennium.par for testing" 10 | elif [ -f "input/mini-millennium.par" ]; then 11 | PARAM_FILE="input/mini-millennium.par" 12 | echo "Using mini-millennium.par for testing" 13 | else 14 | # Create a test parameter file if none exists 15 | PARAM_FILE="input/test.par" 16 | mkdir -p input 17 | echo "Creating test parameter file at $PARAM_FILE" 18 | echo "OutputDir = ./output/" > $PARAM_FILE 19 | echo "FileNameGalaxies = model" >> $PARAM_FILE 20 | echo "LastSnapshotNr = 63" >> $PARAM_FILE 21 | echo "FirstFile = 0" >> $PARAM_FILE 22 | echo "NumFiles = 8" >> $PARAM_FILE 23 | echo "Hubble_h = 0.73" >> $PARAM_FILE 24 | echo "IMF_Type = 1" >> $PARAM_FILE 25 | fi 26 | 27 | # Create output directory if it doesn't exist 28 | mkdir -p output/test-plots 29 | 30 | echo "=== Testing Stellar Mass Function ===" 31 | python output/sage-plot/sage-plot.py --param-file=$PARAM_FILE --output-dir=output/test-plots --plots=stellar_mass_function 32 | 33 | echo "=== Testing Evolution Plots ===" 34 | python output/sage-plot/sage-plot.py --param-file=$PARAM_FILE --output-dir=output/test-plots --plots=sfr_density_evolution --evolution-plots 35 | 36 | echo "=== Tests Complete ===" 37 | echo "Check output/test-plots directory for results" 38 | -------------------------------------------------------------------------------- /code/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef CONSTANTS_H 2 | #define CONSTANTS_H 3 | 4 | /* Floating-point comparison epsilon values */ 5 | #define EPSILON_SMALL 1.0e-10 /* For near-zero comparisons */ 6 | #define EPSILON_MEDIUM 1.0e-6 /* For general equality comparisons */ 7 | #define EPSILON_LARGE 1.0e-4 /* For physics model thresholds */ 8 | 9 | /* Numerical constants for the simulation */ 10 | #define NDIM 3 11 | #define STEPS 10 /* Number of integration intervals between two snapshots */ 12 | #define MAXGALFAC 5 13 | #define ALLOCPARAMETER 10.0 14 | #define MAX_NODE_NAME_LEN 50 15 | #define ABSOLUTEMAXSNAPS \ 16 | 1000 /* The largest number of snapshots for any simulation */ 17 | #define MAXTAGS 300 /* Max number of parameters */ 18 | #define MAX_STRING_LEN 1024 /* Max length of a string containing a name */ 19 | 20 | /* Memory allocation parameters */ 21 | #define GALAXY_ARRAY_GROWTH_FACTOR \ 22 | 1.5 /* Factor to grow arrays by (1.5 = 50% growth) */ 23 | #define MIN_GALAXY_ARRAY_GROWTH \ 24 | 1000 /* Minimum growth increment regardless of factor */ 25 | #define MAX_GALAXY_ARRAY_SIZE \ 26 | 1000000000 /* Upper limit to prevent excessive allocation */ 27 | #define INITIAL_FOF_GALAXIES 1000 /* Initial size for FOF galaxy arrays */ 28 | 29 | /* Physical constants */ 30 | #define GRAVITY 6.672e-8 31 | #define SOLAR_MASS 1.989e33 32 | #define SOLAR_LUM 3.826e33 33 | #define RAD_CONST 7.565e-15 34 | #define AVOGADRO 6.0222e23 35 | #define BOLTZMANN 1.3806e-16 36 | #define GAS_CONST 8.31425e7 37 | #define C 2.9979e10 38 | #define PLANCK 6.6262e-27 39 | #define CM_PER_MPC 3.085678e24 40 | #define PROTONMASS 1.6726e-24 41 | #define HUBBLE 3.2407789e-18 /* in h/sec */ 42 | 43 | #define SEC_PER_MEGAYEAR 3.155e13 44 | #define SEC_PER_YEAR 3.155e7 45 | 46 | /* Data type IDs */ 47 | #define DOUBLE 1 48 | #define STRING 2 49 | #define INT 3 50 | 51 | #endif /* #ifndef CONSTANTS_H */ 52 | -------------------------------------------------------------------------------- /code/util_numeric.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file util_numeric.c 3 | * @brief Implementation of utility functions for numerical stability 4 | * 5 | * This file implements utility functions to improve numerical stability in 6 | * floating-point operations throughout the SAGE codebase. It provides 7 | * safer alternatives to direct comparison operations, division, and 8 | * value bounds checking. 9 | */ 10 | 11 | #include "util_numeric.h" 12 | #include "constants.h" 13 | #include "util_error.h" 14 | #include 15 | #include 16 | #include 17 | 18 | /* Check if value is effectively zero (within EPSILON_SMALL) */ 19 | bool is_zero(double x) { return fabs(x) < EPSILON_SMALL; } 20 | 21 | /* Check if two values are equal within EPSILON_MEDIUM */ 22 | bool is_equal(double x, double y) { return fabs(x - y) < EPSILON_MEDIUM; } 23 | 24 | /* Check if x is definitely greater than y */ 25 | bool is_greater(double x, double y) { return x > y + EPSILON_SMALL; } 26 | 27 | /* Check if x is definitely less than y */ 28 | bool is_less(double x, double y) { return x < y - EPSILON_SMALL; } 29 | 30 | /* Check if x is greater than or equal to y */ 31 | bool is_greater_or_equal(double x, double y) { return x >= y - EPSILON_SMALL; } 32 | 33 | /* Check if x is less than or equal to y */ 34 | bool is_less_or_equal(double x, double y) { return x <= y + EPSILON_SMALL; } 35 | 36 | /* Check if value is within range [min, max] */ 37 | bool is_within(double x, double min, double max) { 38 | return is_greater_or_equal(x, min) && is_less_or_equal(x, max); 39 | } 40 | 41 | /* Perform division with protection against division by zero */ 42 | double safe_div(double num, double denom, double default_val) { 43 | if (is_zero(denom)) { 44 | return default_val; 45 | } 46 | return num / denom; 47 | } 48 | 49 | /* Clamp value between minimum and maximum bounds */ 50 | double clamp(double val, double min, double max) { 51 | if (val < min) 52 | return min; 53 | if (val > max) 54 | return max; 55 | return val; 56 | } 57 | 58 | /* Check if value is finite (not NaN or infinity) */ 59 | bool is_finite_value(double x) { return isfinite(x); } 60 | 61 | /* Calculate sign of value (-1, 0, or 1) */ 62 | int sign(double x) { 63 | if (is_zero(x)) 64 | return 0; 65 | return x < 0 ? -1 : 1; 66 | } 67 | -------------------------------------------------------------------------------- /code/doc_standards.md: -------------------------------------------------------------------------------- 1 | # SAGE Documentation Standards 2 | 3 | ## Function Documentation Template 4 | 5 | Every significant function in the codebase should include a header comment that follows this structure: 6 | 7 | ```c 8 | /** 9 | * @brief Brief description of what the function does 10 | * 11 | * @param param1 Description of first parameter 12 | * @param param2 Description of second parameter 13 | * ... 14 | * @return Description of return value (if applicable) 15 | * 16 | * Detailed description of the function, including: 17 | * - Purpose and functionality 18 | * - Algorithm explanation for complex functions 19 | * - References to scientific papers or equations (if applicable) 20 | * - Edge cases or special considerations 21 | * - Relation to other functions 22 | * - Usage examples (when helpful) 23 | */ 24 | ``` 25 | 26 | ## File Documentation Template 27 | 28 | Each source file should start with a header comment that explains: 29 | 30 | ```c 31 | /** 32 | * @file filename.c 33 | * @brief Brief description of file contents 34 | * 35 | * Detailed description of the file's purpose, what functionality 36 | * it provides, and how it relates to other components. 37 | * 38 | * Key functions: 39 | * - function1(): Brief description 40 | * - function2(): Brief description 41 | * 42 | * References: 43 | * - Paper/publication references if applicable 44 | */ 45 | ``` 46 | 47 | ## Inline Comments 48 | 49 | Inline comments should be used to explain: 50 | - Complex calculations and their physical meaning 51 | - Non-obvious algorithm steps 52 | - Magic numbers or hardcoded values 53 | - Potential pitfalls or edge cases 54 | 55 | Format for inline comments: 56 | - Use `//` for single-line comments 57 | - Place comments before the code they describe 58 | - For multi-line explanations, use `/* ... */` 59 | - Keep comments concise and focused 60 | 61 | ## Variable Naming and Documentation 62 | 63 | - All global variables should have explanatory comments in their declaration files 64 | - Complex data structures should have member descriptions 65 | - Units should be explicitly stated for physical quantities (e.g., Msun/h, Mpc/h, km/s) 66 | 67 | ## Documentation Maintenance 68 | 69 | - Update documentation when code is modified 70 | - Keep documentation synchronized with actual behavior 71 | - Use consistent terminology throughout 72 | -------------------------------------------------------------------------------- /code/globals.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALS_H 2 | #define GLOBALS_H 3 | 4 | #include "constants.h" 5 | #include "types.h" 6 | #include 7 | 8 | /* Global configuration structure */ 9 | extern struct SageConfig SageConfig; 10 | 11 | /* Global simulation state structure */ 12 | extern struct SimulationState SimState; 13 | 14 | #ifdef MPI 15 | extern int ThisTask, NTask, nodeNameLen; 16 | extern char *ThisNode; 17 | #endif 18 | 19 | /* galaxy data pointers */ 20 | extern struct GALAXY *Gal, *HaloGal; 21 | extern struct halo_data *Halo; 22 | extern struct halo_aux_data *HaloAux; 23 | 24 | /* runtime file information */ 25 | extern int Ntrees; /* number of trees in current file */ 26 | extern int NumGals; /* Total number of galaxies stored for current tree */ 27 | extern int MaxGals; /* Maximum number of galaxies allowed for current tree */ 28 | extern int FoF_MaxGals; 29 | extern int 30 | GalaxyCounter; /* unique galaxy ID for main progenitor line in tree */ 31 | 32 | /* halo information */ 33 | extern int TotHalos; 34 | extern int TotGalaxies[ABSOLUTEMAXSNAPS]; 35 | extern int *TreeNgals[ABSOLUTEMAXSNAPS]; 36 | extern int *FirstHaloInSnap; 37 | extern int *TreeNHalos; 38 | extern int *TreeFirstHalo; 39 | 40 | /* parameter handling globals */ 41 | extern int NParam; 42 | extern char ParamTag[MAXTAGS][50]; 43 | extern int ParamID[MAXTAGS]; 44 | extern void *ParamAddr[MAXTAGS]; 45 | 46 | /* derived values from parameters */ 47 | extern double EnergySNcode, EtaSNcode; 48 | 49 | /* units */ 50 | extern double UnitLength_in_cm, UnitTime_in_s, UnitVelocity_in_cm_per_s, 51 | UnitMass_in_g, RhoCrit, UnitPressure_in_cgs, UnitDensity_in_cgs, 52 | UnitCoolingRate_in_cgs, UnitEnergy_in_cgs, UnitTime_in_Megayears, G, Hubble, 53 | a0, ar; 54 | 55 | /* output snapshots - kept for backward compatibility */ 56 | extern int ListOutputSnaps[ABSOLUTEMAXSNAPS]; 57 | extern double ZZ[ABSOLUTEMAXSNAPS]; 58 | extern double AA[ABSOLUTEMAXSNAPS]; 59 | extern double *Age; 60 | extern int MAXSNAPS; 61 | extern int NOUT; 62 | extern int Snaplistlen; 63 | 64 | /* Random number generator removed - not used in computation */ 65 | 66 | /* tree and file information */ 67 | extern int TreeID; 68 | extern int FileNum; 69 | 70 | /* HDF5 specific globals */ 71 | #ifdef HDF5 72 | extern int HDF5Output; 73 | extern char *core_output_file; 74 | extern size_t HDF5_dst_size; 75 | extern size_t *HDF5_dst_offsets; 76 | extern size_t *HDF5_dst_sizes; 77 | extern const char **HDF5_field_names; 78 | extern hid_t *HDF5_field_types; 79 | extern int HDF5_n_props; 80 | #endif 81 | 82 | #endif /* #ifndef GLOBALS_H */ 83 | -------------------------------------------------------------------------------- /code/util_integration.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file util_integration.h 3 | * @brief Numerical integration utilities for SAGE 4 | * 5 | * This file provides highly accurate numerical integration functions used 6 | * in the SAGE codebase. It implements adaptive integration methods for 7 | * precise calculations of cosmological quantities. 8 | */ 9 | 10 | #include // For size_t definition 11 | 12 | #ifndef UTIL_INTEGRATION_H 13 | #define UTIL_INTEGRATION_H 14 | 15 | /* Constants for integration methods */ 16 | #define INTEG_GAUSS15 1 17 | #define INTEG_GAUSS21 2 18 | #define INTEG_GAUSS31 3 19 | #define INTEG_GAUSS41 4 20 | #define INTEG_GAUSS51 5 21 | #define INTEG_GAUSS61 6 22 | 23 | /** 24 | * @brief Function pointer type for the integrand function 25 | */ 26 | typedef double (*integrand_func_t)(double x, void *params); 27 | 28 | /** 29 | * @brief Structure to hold integration function and parameters 30 | */ 31 | typedef struct { 32 | integrand_func_t function; /**< Pointer to the integrand function */ 33 | void *params; /**< Parameters to pass to the integrand function */ 34 | } integration_function_t; 35 | 36 | /** 37 | * @brief Integration workspace structure 38 | * 39 | * This structure holds the workspace for numerical integration. 40 | * Current implementation only tracks size. 41 | */ 42 | typedef struct { 43 | int size; /**< Workspace size */ 44 | } integration_workspace_t; 45 | 46 | /** 47 | * @brief Allocate integration workspace (simplified) 48 | * 49 | * @param size Size parameter (not actually used) 50 | * @return Pointer to workspace 51 | */ 52 | integration_workspace_t *integration_workspace_alloc(size_t size); 53 | 54 | /** 55 | * @brief Free integration workspace (simplified) 56 | * 57 | * @param workspace Pointer to workspace to free 58 | */ 59 | void integration_workspace_free(integration_workspace_t *workspace); 60 | 61 | /** 62 | * @brief Adaptive integration for high-accuracy numerical integration 63 | * 64 | * Implements adaptive integration using Simpson's rule for high-accuracy 65 | * calculation of definite integrals. Suitable for smooth functions like 66 | * those encountered in cosmological calculations. 67 | * 68 | * @param f Integration function structure 69 | * @param a Lower integration limit 70 | * @param b Upper integration limit 71 | * @param epsabs Absolute error tolerance 72 | * @param epsrel Relative error tolerance 73 | * @param limit Maximum number of subintervals 74 | * @param key Integration rule to use (see INTEG_* constants) 75 | * @param workspace Integration workspace 76 | * @param result Pointer to store integration result 77 | * @param abserr Pointer to store error estimate 78 | * @return Status code (0 for success) 79 | */ 80 | int integration_qag(integration_function_t *f, double a, double b, 81 | double epsabs, double epsrel, size_t limit, int key, 82 | integration_workspace_t *workspace, double *result, 83 | double *abserr); 84 | 85 | #endif /* UTIL_INTEGRATION_H */ 86 | -------------------------------------------------------------------------------- /code/core_allvars.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file core_allvars.c 3 | * @brief Defines global variables used throughout the SAGE model 4 | * 5 | * This file contains the definitions of all global variables used by the 6 | * SAGE model. These variables fall into several categories: 7 | * 8 | * 1. Core data structures (galaxies, halos, and auxiliary data) 9 | * 2. Configuration parameters and derived values 10 | * 3. Simulation state variables (counts, indices, etc.) 11 | * 4. Physical constants and units 12 | * 5. File and output control variables 13 | * 14 | * Many of these global variables are being gradually migrated to the 15 | * SageConfig and SimState structures to improve encapsulation and make 16 | * the code more maintainable, but they are kept for backward compatibility 17 | * with existing code. New code should preferentially use the structured 18 | * approach rather than accessing these globals directly. 19 | * 20 | * Note: This file contains only variable definitions - the declarations 21 | * are in globals.h and other header files. 22 | */ 23 | 24 | #include "config.h" 25 | #include "globals.h" 26 | #include "types.h" 27 | 28 | /* Global configuration structure */ 29 | struct SageConfig SageConfig; 30 | 31 | /* Global simulation state structure */ 32 | struct SimulationState SimState; 33 | 34 | /* galaxy data */ 35 | struct GALAXY *Gal, *HaloGal; 36 | 37 | struct halo_data *Halo; 38 | 39 | /* auxiliary halo data */ 40 | struct halo_aux_data *HaloAux; 41 | 42 | /* misc */ 43 | 44 | int HDF5Output; 45 | #ifdef HDF5 46 | char *core_output_file; 47 | size_t HDF5_dst_size; 48 | size_t *HDF5_dst_offsets; 49 | size_t *HDF5_dst_sizes; 50 | const char **HDF5_field_names; 51 | hid_t *HDF5_field_types; 52 | int HDF5_n_props; 53 | #endif 54 | 55 | int MaxGals; 56 | int FoF_MaxGals; 57 | int Ntrees; /* number of trees in current file */ 58 | int NumGals; /* Total number of galaxies stored for current tree */ 59 | 60 | int GalaxyCounter; /* unique galaxy ID for main progenitor line in tree */ 61 | 62 | int TotHalos; 63 | int TotGalaxies[ABSOLUTEMAXSNAPS]; 64 | int *TreeNgals[ABSOLUTEMAXSNAPS]; 65 | 66 | int LastSnapshotNr; 67 | double BoxSize; 68 | 69 | int *FirstHaloInSnap; 70 | int *TreeNHalos; 71 | int *TreeFirstHalo; 72 | 73 | #ifdef MPI 74 | int ThisTask, NTask, nodeNameLen; 75 | char *ThisNode; 76 | #endif 77 | 78 | /* recipe parameters */ 79 | int NParam; 80 | char ParamTag[MAXTAGS][50]; 81 | int ParamID[MAXTAGS]; 82 | void *ParamAddr[MAXTAGS]; 83 | 84 | /* derived values from parameters */ 85 | double EnergySNcode; 86 | double EtaSNcode; 87 | 88 | /* more misc - kept for backward compatibility */ 89 | double UnitLength_in_cm, UnitTime_in_s, UnitVelocity_in_cm_per_s, UnitMass_in_g, 90 | RhoCrit, UnitPressure_in_cgs, UnitDensity_in_cgs, UnitCoolingRate_in_cgs, 91 | UnitEnergy_in_cgs, UnitTime_in_Megayears, G, Hubble, a0, ar; 92 | 93 | int ListOutputSnaps[ABSOLUTEMAXSNAPS]; 94 | double ZZ[ABSOLUTEMAXSNAPS]; 95 | double AA[ABSOLUTEMAXSNAPS]; 96 | double *Age; 97 | 98 | int MAXSNAPS; 99 | int NOUT; 100 | int Snaplistlen; 101 | 102 | /* derived values from parameters */ 103 | double EnergySNcode; 104 | double EtaSNcode; 105 | 106 | /* Random number generator removed - not used in computation */ 107 | 108 | int TreeID; 109 | int FileNum; 110 | 111 | enum Valid_TreeTypes TreeType; 112 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # USE-MPI = yes # set this if you want to run in embarrassingly parallel 2 | # USE-HDF5 = yes # set this if you want to read in hdf5 trees (requires hdf5 libraries) 3 | 4 | LIBS := 5 | CFLAGS := 6 | OPT := 7 | 8 | EXEC := sage 9 | OBJS := ./code/main.o \ 10 | ./code/util_parameters.o \ 11 | ./code/util_error.o \ 12 | ./code/util_integration.o \ 13 | ./code/util_numeric.o \ 14 | ./code/util_version.o \ 15 | ./code/io_util.o \ 16 | ./code/core_read_parameter_file.o \ 17 | ./code/core_init.o \ 18 | ./code/io_tree.o \ 19 | ./code/core_cool_func.o \ 20 | ./code/core_build_model.o \ 21 | ./code/io_save_binary.o \ 22 | ./code/util_memory.o \ 23 | ./code/core_allvars.o \ 24 | ./code/core_simulation_state.o \ 25 | ./code/model_infall.o \ 26 | ./code/model_cooling_heating.o \ 27 | ./code/model_starformation_and_feedback.o \ 28 | ./code/model_disk_instability.o \ 29 | ./code/model_reincorporation.o \ 30 | ./code/model_mergers.o \ 31 | ./code/model_misc.o \ 32 | ./code/io_tree_binary.o 33 | 34 | INCL := ./code/core_allvars.h \ 35 | ./code/io_tree.h \ 36 | ./code/io_save_binary.h \ 37 | ./code/util_memory.h \ 38 | ./code/util_integration.h \ 39 | ./code/util_numeric.h \ 40 | ./code/util_version.h \ 41 | ./code/io_util.h \ 42 | ./code/core_proto.h \ 43 | ./code/core_simulation.h \ 44 | ./code/util_parameters.h \ 45 | ./code/util_error.h \ 46 | ./code/config.h \ 47 | ./code/constants.h \ 48 | ./code/globals.h \ 49 | ./code/types.h \ 50 | ./code/io_tree_binary.h \ 51 | ./Makefile 52 | 53 | ifdef USE-MPI 54 | OPT += -DMPI # This creates an MPI version that can be used to process files in parallel 55 | CC = mpicc # sets the C-compiler 56 | else 57 | CC = cc # sets the C-compiler 58 | endif 59 | 60 | ifdef USE-HDF5 61 | HDF5DIR := usr/local/x86_64/gnu/hdf5-1.8.17-openmpi-1.10.2-psm 62 | HDF5INCL := -I$(HDF5DIR)/include 63 | HDF5LIB := -L$(HDF5DIR)/lib -lhdf5 -Xlinker -rpath -Xlinker $(HDF5DIR)/lib 64 | 65 | OBJS += ./code/io_tree_hdf5.o ./code/io_save_hdf5.o 66 | INCL += ./code/io_tree_hdf5.h ./code/io_save_hdf5.h 67 | 68 | OPT += -DHDF5 69 | LIBS += $(HDF5LIB) 70 | CFLAGS += $(HDF5INCL) 71 | endif 72 | 73 | # Path to the Git version header files 74 | GIT_VERSION_IN = ./code/git_version.h.in 75 | GIT_VERSION_H = ./code/git_version.h 76 | 77 | # GSL dependency removed - using custom implementations instead 78 | 79 | OPTIMIZE = -g -O0 -Wall # optimization and warning flags 80 | 81 | LIBS += -g -lm 82 | CFLAGS += $(OPTIONS) $(OPT) $(OPTIMIZE) 83 | 84 | 85 | default: all 86 | 87 | # Generate the Git version header file 88 | $(GIT_VERSION_H): $(GIT_VERSION_IN) 89 | @echo "Generating Git version header" 90 | @sed -e "s/@GIT_COMMIT_HASH@/$(shell git rev-parse HEAD)/g" \ 91 | -e "s/@GIT_BRANCH_NAME@/$(shell git rev-parse --abbrev-ref HEAD)/g" \ 92 | $(GIT_VERSION_IN) > $(GIT_VERSION_H) 93 | 94 | $(EXEC): $(OBJS) 95 | $(CC) $(OPTIMIZE) $(OBJS) $(LIBS) -o $(EXEC) 96 | 97 | $(OBJS): $(INCL) $(GIT_VERSION_H) 98 | 99 | # Mark git_version.h as PHONY to ensure it's regenerated with each build 100 | # This ensures the git information is always current, even without cleaning 101 | .PHONY: $(GIT_VERSION_H) 102 | 103 | clean: 104 | rm -f $(OBJS) $(EXEC) $(GIT_VERSION_H) 105 | 106 | tidy: 107 | rm -f $(OBJS) ./$(EXEC) 108 | 109 | all: $(EXEC) 110 | 111 | -------------------------------------------------------------------------------- /code/model_reincorporation.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file model_reincorporation.c 3 | * @brief Implementation of gas reincorporation from ejected reservoir 4 | * 5 | * This file implements the physical model for the reincorporation of gas 6 | * that was previously ejected from galaxies by powerful feedback events. 7 | * The reincorporation rate depends on the virial velocity of the halo, 8 | * with more massive halos able to recapture their ejected gas more efficiently. 9 | * 10 | * The model is based on the concept that supernova-driven winds can escape 11 | * the gravitational potential of low-mass halos but may be recaptured by 12 | * more massive halos. Gas reincorporation becomes effective when the halo's 13 | * escape velocity exceeds the characteristic velocity of supernova-driven 14 | * winds. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "core_allvars.h" 24 | #include "core_proto.h" 25 | #include "util_numeric.h" 26 | 27 | /** 28 | * @brief Reincorporates gas from the ejected reservoir back into the hot halo 29 | * 30 | * @param centralgal Index of the central galaxy 31 | * @param dt Time step size 32 | * 33 | * This function models the reincorporation of gas that was previously ejected 34 | * from the galaxy due to supernova feedback. The reincorporation rate depends 35 | * on: 36 | * 37 | * 1. The ratio of the halo's virial velocity to a critical velocity (Vcrit) 38 | * 2. The amount of gas in the ejected reservoir 39 | * 3. The dynamical time of the halo (Rvir/Vvir) 40 | * 41 | * Reincorporation only occurs in halos with virial velocities exceeding the 42 | * critical velocity, which is related to the characteristic velocity of 43 | * supernova-driven winds. The rate increases for more massive halos (higher 44 | * Vvir). 45 | * 46 | * Metals are reincorporated along with the gas, preserving the metallicity of 47 | * the ejected reservoir. 48 | */ 49 | void reincorporate_gas(int centralgal, double dt) { 50 | double reincorporated, metallicity; 51 | 52 | /* Critical velocity for reincorporation 53 | * SN velocity is ~630km/s, and reincorporation occurs when the halo escape 54 | * velocity exceeds this value. The escape velocity relates to virial velocity 55 | * as V_esc = sqrt(2)*V_vir, so the critical virial velocity is V_SN/sqrt(2) = 56 | * 445.48 km/s This is modified by a tunable parameter ReIncorporationFactor 57 | */ 58 | double Vcrit = 445.48 * SageConfig.ReIncorporationFactor; 59 | 60 | /* Only reincorporate gas if the halo virial velocity exceeds the critical 61 | * value */ 62 | if (is_greater(Gal[centralgal].Vvir, Vcrit)) { 63 | /* Calculate reincorporation rate: 64 | * Rate = (Vvir/Vcrit - 1) * Mejected / tdyn * dt 65 | * Where tdyn is the dynamical time of the halo (Rvir/Vvir) */ 66 | reincorporated = 67 | (safe_div(Gal[centralgal].Vvir, Vcrit, EPSILON_SMALL) - 1.0) * 68 | Gal[centralgal].EjectedMass * 69 | safe_div(Gal[centralgal].Vvir, Gal[centralgal].Rvir, EPSILON_SMALL) * 70 | dt; 71 | 72 | /* Limit reincorporation to the available ejected mass */ 73 | if (is_greater(reincorporated, Gal[centralgal].EjectedMass)) 74 | reincorporated = Gal[centralgal].EjectedMass; 75 | 76 | /* Calculate metallicity of ejected gas */ 77 | metallicity = get_metallicity(Gal[centralgal].EjectedMass, 78 | Gal[centralgal].MetalsEjectedMass); 79 | 80 | /* Update galaxy components */ 81 | Gal[centralgal].EjectedMass -= 82 | reincorporated; /* Remove from ejected reservoir */ 83 | Gal[centralgal].MetalsEjectedMass -= 84 | metallicity * reincorporated; /* Remove metals */ 85 | 86 | Gal[centralgal].HotGas += reincorporated; /* Add to hot gas reservoir */ 87 | Gal[centralgal].MetalsHotGas += 88 | metallicity * reincorporated; /* Add metals */ 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /input/millennium.par: -------------------------------------------------------------------------------- 1 | %------------------------------------------ 2 | %----- SAGE output file information ------- 3 | %------------------------------------------ 4 | 5 | FileNameGalaxies model 6 | OutputDir ./output/results/millennium/ 7 | 8 | FirstFile 0 9 | LastFile 7 10 | 11 | 12 | %------------------------------------------ 13 | %----- Snapshot output list --------------- 14 | %------------------------------------------ 15 | 16 | NumOutputs 8 ; sets the desired number of galaxy outputs; use -1 for all outputs 17 | 18 | % List your output snapshots after the arrow, highest to lowest (ignored when NumOutputs=-1). 19 | -> 63 37 32 27 23 20 18 16 20 | 21 | 22 | %------------------------------------------ 23 | %----- Simulation information ------------ 24 | %------------------------------------------ 25 | 26 | TreeName trees_063 ; assumes the trees are named TreeName.n where n is the file number 27 | TreeType lhalo_binary ; either 'genesis_lhalo_hdf5' or 'lhalo_binary' 28 | 29 | SimulationDir ./input/data/millennium/ 30 | FileWithSnapList ./input/data/millennium/millennium.a_list 31 | LastSnapshotNr 63 32 | NumSimulationTreeFiles 8 ; not used but needed for plotting 33 | BoxSize 62.5 ; in Mpc/h - not used but needed for plotting 34 | 35 | Omega 0.25 36 | OmegaLambda 0.75 37 | BaryonFrac 0.17 38 | Hubble_h 0.73 39 | 40 | PartMass 0.0860657 41 | 42 | 43 | %------------------------------------------ 44 | %----- SAGE recipe options ---------------- 45 | %------------------------------------------ 46 | 47 | SFprescription 0 ;0: original Croton et al. 2006 48 | AGNrecipeOn 2 ;0: switch off; 1: empirical model; 2: Bondi-Hoyle model; 3: cold cloud accretion model 49 | SupernovaRecipeOn 1 ;0: switch off 50 | ReionizationOn 1 ;0: switch off 51 | DiskInstabilityOn 1 ;0: switch off; 1: bulge and BH growth through instabilities w. instability starbursts 52 | 53 | 54 | %------------------------------------------ 55 | %----- SAGE model parameters -------------- 56 | %------------------------------------------ 57 | 58 | SfrEfficiency 0.05 ;efficiency of SF (SFprescription=0) 59 | 60 | FeedbackReheatingEpsilon 3.0 ;mass of cold gas reheated due to SF (see Martin 1999) (SupernovaRecipeOn=1) 61 | FeedbackEjectionEfficiency 0.3 ;mixing efficiency of SN energy with hot gas to unbind and eject some (SupernovaRecipeOn=1) 62 | 63 | ReIncorporationFactor 0.15 ;fraction of ejected mass reincorporated per dynamical time to hot 64 | 65 | RadioModeEfficiency 0.08 ;AGN radio mode efficiency (AGNrecipeOn=2) 66 | QuasarModeEfficiency 0.005 ;AGN quasar mode wind heating efficiency (AGNrecipeOn>0) 67 | BlackHoleGrowthRate 0.015 ;fraction of cold gas added to the BH during mergers (AGNrecipeOn>0) 68 | 69 | ThreshMajorMerger 0.3 ;major merger when mass ratio greater than this 70 | ThresholdSatDisruption 1.0 ;Mvir-to-baryonic mass ratio threshold for satellite merger or disruption 71 | 72 | Yield 0.025 ;fraction of SF mass produced as metals 73 | RecycleFraction 0.43 ;fraction of SF mass instantaneously recycled back to cold 74 | FracZleaveDisk 0.0 ;fraction of metals produced directly to hot component 75 | 76 | Reionization_z0 8.0 ;these parameter choices give the best fit to Genedin (2000)... 77 | Reionization_zr 7.0 ;using the analytic fit of Kravtsov et al. 2004 (ReionizationOn=1) 78 | 79 | EnergySN 1.0e51 ;energy per supernova 80 | EtaSN 5.0e-3 ;supernova efficiency 81 | 82 | 83 | %------------------------------------------ 84 | %----- Other code-related information ----- 85 | %------------------------------------------ 86 | 87 | UnitLength_in_cm 3.08568e+24 ;WATCH OUT: Mpc/h 88 | UnitMass_in_g 1.989e+43 ;WATCH OUT: 10^10Msun 89 | UnitVelocity_in_cm_per_s 100000 ;WATCH OUT: km/s 90 | -------------------------------------------------------------------------------- /code/util_numeric.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_NUMERIC_H 2 | #define UTIL_NUMERIC_H 3 | 4 | #include "constants.h" 5 | #include 6 | #include 7 | 8 | /** 9 | * @file util_numeric.h 10 | * @brief Utility functions for numerical stability and safer floating-point 11 | * operations 12 | * 13 | * This file provides utility functions to improve numerical stability in 14 | * the SAGE codebase by offering safer floating-point comparison operations, 15 | * division checks, and value validation functions. Using these utilities 16 | * instead of direct floating-point operations helps avoid common numerical 17 | * issues. 18 | */ 19 | 20 | /** 21 | * @brief Checks if a value is effectively zero (within EPSILON_SMALL) 22 | * 23 | * @param x The value to check 24 | * @return true if |x| < EPSILON_SMALL, false otherwise 25 | */ 26 | bool is_zero(double x); 27 | 28 | /** 29 | * @brief Checks if two values are equal within EPSILON_MEDIUM 30 | * 31 | * @param x First value to compare 32 | * @param y Second value to compare 33 | * @return true if |x-y| < EPSILON_MEDIUM, false otherwise 34 | */ 35 | bool is_equal(double x, double y); 36 | 37 | /** 38 | * @brief Checks if x is definitely greater than y (accounting for 39 | * floating-point error) 40 | * 41 | * @param x First value to compare 42 | * @param y Second value to compare 43 | * @return true if x > y + EPSILON_SMALL, false otherwise 44 | */ 45 | bool is_greater(double x, double y); 46 | 47 | /** 48 | * @brief Checks if x is definitely less than y (accounting for floating-point 49 | * error) 50 | * 51 | * @param x First value to compare 52 | * @param y Second value to compare 53 | * @return true if x < y - EPSILON_SMALL, false otherwise 54 | */ 55 | bool is_less(double x, double y); 56 | 57 | /** 58 | * @brief Checks if x is greater than or equal to y (accounting for 59 | * floating-point error) 60 | * 61 | * @param x First value to compare 62 | * @param y Second value to compare 63 | * @return true if x >= y - EPSILON_SMALL, false otherwise 64 | */ 65 | bool is_greater_or_equal(double x, double y); 66 | 67 | /** 68 | * @brief Checks if x is less than or equal to y (accounting for 69 | * floating-point error) 70 | * 71 | * @param x First value to compare 72 | * @param y Second value to compare 73 | * @return true if x <= y + EPSILON_SMALL, false otherwise 74 | */ 75 | bool is_less_or_equal(double x, double y); 76 | 77 | /** 78 | * @brief Checks if a value is within a specified range (inclusive) 79 | * 80 | * @param x Value to check 81 | * @param min Minimum acceptable value 82 | * @param max Maximum acceptable value 83 | * @return true if min <= x <= max (accounting for floating-point error), false 84 | * otherwise 85 | */ 86 | bool is_within(double x, double min, double max); 87 | 88 | /** 89 | * @brief Performs division with protection against division by zero 90 | * 91 | * @param num Numerator 92 | * @param denom Denominator 93 | * @param default_val Value to return if denominator is zero 94 | * @return num/denom if denom is not zero, default_val otherwise 95 | */ 96 | double safe_div(double num, double denom, double default_val); 97 | 98 | /** 99 | * @brief Clamps a value between minimum and maximum bounds 100 | * 101 | * @param val Value to clamp 102 | * @param min Minimum bound 103 | * @param max Maximum bound 104 | * @return Value clamped to the range [min, max] 105 | */ 106 | double clamp(double val, double min, double max); 107 | 108 | /** 109 | * @brief Checks if a value is finite (not NaN or infinity) 110 | * 111 | * @param x Value to check 112 | * @return true if x is a finite number, false otherwise 113 | */ 114 | bool is_finite_value(double x); 115 | 116 | /** 117 | * @brief Calculates the sign of a value (-1, 0, or 1) 118 | * 119 | * @param x Value to get sign of 120 | * @return -1 if x < 0, 0 if x is zero, 1 if x > 0 121 | */ 122 | int sign(double x); 123 | 124 | #endif /* UTIL_NUMERIC_H */ 125 | -------------------------------------------------------------------------------- /code/util_error.h: -------------------------------------------------------------------------------- 1 | #ifndef ERROR_HANDLING_H 2 | #define ERROR_HANDLING_H 3 | 4 | #include 5 | 6 | /** 7 | * Error severity levels 8 | */ 9 | typedef enum { 10 | LOG_LEVEL_DEBUG, // Detailed debugging information (function tracing, variable 11 | // values, etc.) 12 | LOG_LEVEL_INFO, // General informational messages (processing milestones, 13 | // configuration info) 14 | LOG_LEVEL_WARNING, // Warnings that don't stop execution (unusual but 15 | // acceptable conditions) 16 | LOG_LEVEL_ERROR, // Recoverable errors (operation failed but program can 17 | // continue) 18 | LOG_LEVEL_FATAL // Unrecoverable errors that terminate execution (critical 19 | // failures) 20 | } LogLevel; 21 | 22 | /** 23 | * I/O-specific error codes 24 | */ 25 | typedef enum { 26 | IO_ERROR_NONE = 0, // No error 27 | IO_ERROR_FILE_NOT_FOUND = 1, // File not found or couldn't be opened 28 | IO_ERROR_PERMISSION_DENIED = 2, // Permission denied for file operation 29 | IO_ERROR_READ_FAILED = 3, // Read operation failed 30 | IO_ERROR_WRITE_FAILED = 4, // Write operation failed 31 | IO_ERROR_SEEK_FAILED = 5, // Seek operation failed 32 | IO_ERROR_INVALID_HEADER = 6, // Invalid or corrupted file header 33 | IO_ERROR_VERSION_MISMATCH = 7, // File version incompatible 34 | IO_ERROR_ENDIANNESS = 8, // Endianness-related error 35 | IO_ERROR_FORMAT = 9, // General file format error 36 | IO_ERROR_BUFFER = 10, // Buffer management error 37 | IO_ERROR_EOF = 11, // Unexpected end of file 38 | IO_ERROR_CLOSE_FAILED = 12, // Failed to close file 39 | IO_ERROR_HDF5 = 13 // HDF5-specific error 40 | } IOErrorCode; 41 | 42 | // General error handling function prototypes 43 | void initialize_error_handling(LogLevel min_level, FILE *output_file); 44 | void log_message(LogLevel level, const char *file, const char *func, int line, 45 | const char *format, ...); 46 | void set_log_level(LogLevel min_level); 47 | FILE *set_log_output(FILE *output_file); 48 | 49 | // I/O-specific error handling function prototypes 50 | const char *get_io_error_name(IOErrorCode code); 51 | void log_io_error(LogLevel level, IOErrorCode code, const char *file, 52 | const char *func, int line, const char *operation, 53 | const char *filename, const char *format, ...); 54 | 55 | // General logging convenience macros 56 | #define DEBUG_LOG(...) \ 57 | log_message(LOG_LEVEL_DEBUG, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) 58 | #define INFO_LOG(...) \ 59 | log_message(LOG_LEVEL_INFO, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) 60 | #define WARNING_LOG(...) \ 61 | log_message(LOG_LEVEL_WARNING, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) 62 | #define ERROR_LOG(...) \ 63 | log_message(LOG_LEVEL_ERROR, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) 64 | #define FATAL_ERROR(...) \ 65 | do { \ 66 | log_message(LOG_LEVEL_FATAL, __FILE__, __FUNCTION__, __LINE__, \ 67 | __VA_ARGS__); \ 68 | myexit(1); \ 69 | } while (0) 70 | 71 | // I/O-specific logging macros 72 | #define IO_DEBUG_LOG(code, op, filename, ...) \ 73 | log_io_error(LOG_LEVEL_DEBUG, code, __FILE__, __FUNCTION__, __LINE__, op, \ 74 | filename, __VA_ARGS__) 75 | #define IO_INFO_LOG(code, op, filename, ...) \ 76 | log_io_error(LOG_LEVEL_INFO, code, __FILE__, __FUNCTION__, __LINE__, op, \ 77 | filename, __VA_ARGS__) 78 | #define IO_WARNING_LOG(code, op, filename, ...) \ 79 | log_io_error(LOG_LEVEL_WARNING, code, __FILE__, __FUNCTION__, __LINE__, op, \ 80 | filename, __VA_ARGS__) 81 | #define IO_ERROR_LOG(code, op, filename, ...) \ 82 | log_io_error(LOG_LEVEL_ERROR, code, __FILE__, __FUNCTION__, __LINE__, op, \ 83 | filename, __VA_ARGS__) 84 | #define IO_FATAL_ERROR(code, op, filename, ...) \ 85 | do { \ 86 | log_io_error(LOG_LEVEL_FATAL, code, __FILE__, __FUNCTION__, __LINE__, op, \ 87 | filename, __VA_ARGS__); \ 88 | myexit(1); \ 89 | } while (0) 90 | 91 | // String representation functions 92 | const char *get_log_level_name(LogLevel level); 93 | 94 | #endif /* ERROR_HANDLING_H */ 95 | -------------------------------------------------------------------------------- /extra/CoolFunctions/ABOUT.txt: -------------------------------------------------------------------------------- 1 | ABOUT THE COOLING FUNCTIONS 2 | 3 | The associated files contain the cooling functions calculated for the paper 4 | by R. S. Sutherland and M. A. Dopita to appear in ApJS in 1993. See paper 5 | or preprint for details. 6 | 7 | *****FILE LIST 8 | 9 | 1) Collisonal Ionisation Equilibrium cooling functions as a function 10 | of metallicity are given in the files: 11 | 12 | mzero.cie : cie cooling for primordial hydrogen/helium mix log(T) = 4-8.5 13 | m-00.cie : cie cooling for solar abundances mix log(T) = 4-8.5 14 | m-05.cie : [Fe/H] = -0.5, solar/primordial average ratios 15 | m-10.cie : [Fe/H] = -1.0, primordial ratios (ie enhanced oxygen) 16 | m-15.cie : [Fe/H] = -1.5, primordial ratios 17 | m-20.cie : [Fe/H] = -2.0, primordial ratios 18 | m-30.cie : [Fe/H] = -3.0, primordial ratios 19 | m+05.cie : [Fe/H] = +0.5, solar ratios log(T) = 4.1-8.5 (due to charge 20 | exchange problems at log(T) = 4.0) 21 | 22 | 2) Non-Equilibrium (NEQ) cooling functions as a function 23 | of initial temperature are given in the files: 24 | 25 | a) full internal diffuse field transfer (ie plane parallel case) 26 | pk6ff55.neq : NEQ cooling for solar mix log(T0) = 5.5 down to 4.0 27 | pk6ff65.neq : NEQ cooling for solar mix log(T0) = 6.5 down to 4.0 28 | pk6ff75.neq : NEQ cooling for solar mix log(T0) = 7.5 down to 4.0 29 | pk6ff85.neq : NEQ cooling for solar mix log(T0) = 8.5 down to 4.0 30 | a) Zero internal diffuse field transfer (ie limiting case for fragmenting condensations) 31 | pk6zf55.neq : NEQ cooling for solar mix log(T0) = 5.5 down to 4.0 32 | pk6zf65.neq : NEQ cooling for solar mix log(T0) = 6.5 down to 4.0 33 | pk6zf75.neq : NEQ cooling for solar mix log(T0) = 7.5 down to 4.0 34 | pk6zf85.neq : NEQ cooling for solar mix log(T0) = 8.5 down to 4.0 35 | 36 | 3) Non-Equilibrium (NEQ) cooling functions as a function 37 | of metallicity are given in the files: 38 | 39 | pressure domain of models log(p/k) = 6 40 | 41 | a) full internal diffuse field transfer (ie plane parallel case) 42 | pk6ff75m-05.neq : NEQ [Fe/H] = -0.5; log(T0) = 7.5 down to 4.0 43 | pk6ff75m-10.neq : NEQ [Fe/H] = -1.0; log(T0) = 7.5 down to 4.0 44 | pk6ff75m-15.neq : NEQ [Fe/H] = -1.5; log(T0) = 7.5 down to 4.0 45 | pk6ff75m-20.neq : NEQ [Fe/H] = -2.0; log(T0) = 7.5 down to 4.0 46 | pk6ff75m-30.neq : NEQ [Fe/H] = -3.0; log(T0) = 7.5 down to 4.0 47 | a) Zero internal diffuse field transfer (ie limiting case for fragmenting condensations) 48 | pk6zf75m-05.neq : NEQ [Fe/H] = -0.5; log(T0) = 7.5 down to 4.0 49 | pk6zf75m-10.neq : NEQ [Fe/H] = -1.0; log(T0) = 7.5 down to 4.0 50 | pk6zf75m-15.neq : NEQ [Fe/H] = -1.5; log(T0) = 7.5 down to 4.0 51 | pk6zf75m-20.neq : NEQ [Fe/H] = -2.0; log(T0) = 7.5 down to 4.0 52 | pk6zf75m-30.neq : NEQ [Fe/H] = -3.0; log(T0) = 7.5 down to 4.0 53 | 54 | 55 | *****FILE FORMAT 56 | 57 | The data files consist of tab separated ASCII column data described as follows: 58 | 59 | log(T): log temperature in K 60 | 61 | ne nH nt : number densities, electrons, hydrogen and total ion in cm^-3. 62 | 63 | log(lambda net) log(lambda norm) : log on the net cooling function 64 | and the normalised cooling function. lambda norm = lambda net / (ne nt). 65 | lambda net in ergs cm^-3 s^-1, lambda net in ergs cm^3 s^-1. While the 66 | densities are kept less than about p/k 10^8 both isobaric and isochoric 67 | curves can be constructed from the normalised function using an appropriate 68 | density function. The non-equilibrium net cooling function is from the 69 | isobaric model used to calculate the curves. In the CIE curves the net function 70 | is for the isochoric cie model. 71 | 72 | log(U): U = 3/2 N kT , N = ne + nt the total internal energy. ergs cm^-3 73 | 74 | log(taucool): The normalized cooling timescale Nr*( U/(lambda net)) 75 | Nr = (ne nt)/(ne+nt). s cm^-3 76 | 77 | P12: Gas pressure NkT. ergs ergs cm^-3 times 10^12 78 | 79 | rho24: Density g cm^-3 times 10^24 80 | 81 | Ci: The isothermal sound speed kms s^-1 82 | 83 | mubar: mean molecular weight grams times 10^24 84 | 85 | *****NOTES 86 | 87 | Tests showed that density quenching begins to affect the curves in the low 88 | temperature parts of the cooling functions when log(p/k) = 8 or more. 89 | 90 | Above log(T) = 7.5-8.5 it should be pretty safe to use a powerlaw 91 | fit to the free-free losses 92 | 93 | Good luck, and let me know if you have any problems. 94 | 95 | These files will be available via anonymous ftp from 96 | 97 | merlin.anu.edu.au 98 | 99 | login:anonymous 100 | password: 101 | 102 | they will reside in the /pub/cool. 103 | 104 | If you do not have ftp access, email arrangements can be made. 105 | 106 | Yours sincerely 107 | 108 | Ralph S. Sutherland 1992-1993. 109 | 110 | -- Ralph S. Sutherland Mount Stromlo & Siding Spring Observatories. 111 | -- ralph@merlin.anu.edu.au The Australian National University. 112 | -- rss100@cscgpo.anu.edu.au -------------------------------------------- 113 | 114 | -------------------------------------------------------------------------------- /output/sage-plot/figures/baryonic_tully_fisher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Baryonic Tully-Fisher Relationship Plot 5 | 6 | This module generates a baryonic Tully-Fisher plot from SAGE galaxy data. 7 | """ 8 | 9 | import os 10 | from random import sample, seed 11 | 12 | import matplotlib.pyplot as plt 13 | import numpy as np 14 | from figures import ( 15 | AXIS_LABEL_SIZE, 16 | IN_FIGURE_TEXT_SIZE, 17 | LEGEND_FONT_SIZE, 18 | get_baryonic_mass_label, 19 | get_vmax_label, 20 | setup_legend, 21 | setup_plot_fonts, 22 | ) 23 | from matplotlib.ticker import MultipleLocator 24 | 25 | 26 | def plot( 27 | galaxies, 28 | volume, 29 | metadata, 30 | params, 31 | output_dir="plots", 32 | output_format=".png", 33 | dilute=7500, 34 | verbose=False, 35 | ): 36 | """ 37 | Create a baryonic Tully-Fisher plot. 38 | 39 | Args: 40 | galaxies: Galaxy data as a numpy recarray 41 | volume: Simulation volume in (Mpc/h)^3 42 | metadata: Dictionary with additional metadata 43 | params: Dictionary with SAGE parameters 44 | output_dir: Output directory for the plot 45 | output_format: File format for the output 46 | dilute: Maximum number of points to plot (for clarity) 47 | 48 | Returns: 49 | Path to the saved plot file 50 | """ 51 | # Set random seed for reproducibility when diluting 52 | seed(2222) 53 | 54 | # Extract necessary metadata 55 | hubble_h = metadata["hubble_h"] 56 | 57 | # Set up the figure 58 | fig, ax = plt.subplots(figsize=(8, 6)) 59 | 60 | # Apply consistent font settings 61 | setup_plot_fonts(ax) 62 | 63 | # Select Sb/c galaxies (Type=0 and bulge/total ratio between 0.1 and 0.5) 64 | # First filter for non-zero stellar mass to avoid division by zero 65 | valid_mass = ( 66 | (galaxies.Type == 0) 67 | & (galaxies.StellarMass > 0.0) 68 | & (galaxies.StellarMass + galaxies.ColdGas > 0.0) 69 | ) 70 | 71 | # Then calculate ratios safely 72 | bulge_to_stellar = np.zeros_like(galaxies.StellarMass) 73 | bulge_to_stellar[valid_mass] = ( 74 | galaxies.BulgeMass[valid_mass] / galaxies.StellarMass[valid_mass] 75 | ) 76 | 77 | # Now apply all filters 78 | w = np.where(valid_mass & (bulge_to_stellar > 0.1) & (bulge_to_stellar < 0.5))[0] 79 | 80 | # Check if we have any galaxies to plot 81 | if len(w) == 0: 82 | print("No suitable galaxies found for Tully-Fisher plot") 83 | # Create an empty plot with a message 84 | ax.text( 85 | 0.5, 86 | 0.5, 87 | "No suitable galaxies found for Tully-Fisher plot", 88 | horizontalalignment="center", 89 | verticalalignment="center", 90 | transform=ax.transAxes, 91 | fontsize=IN_FIGURE_TEXT_SIZE, 92 | ) 93 | 94 | # Save the figure 95 | os.makedirs(output_dir, exist_ok=True) 96 | output_path = os.path.join(output_dir, f"BaryonicTullyFisher{output_format}") 97 | plt.savefig(output_path) 98 | plt.close() 99 | return output_path 100 | 101 | # Dilute the sample if needed 102 | if len(w) > dilute: 103 | w = sample(list(w), dilute) 104 | 105 | # Calculate baryonic mass and max velocity 106 | mass = np.log10((galaxies.StellarMass[w] + galaxies.ColdGas[w]) * 1.0e10 / hubble_h) 107 | vel = np.log10(galaxies.Vmax[w]) 108 | 109 | # Plot the model galaxies 110 | ax.scatter( 111 | vel, mass, marker="o", s=1, c="k", alpha=0.5, label="Model Sb/c galaxies" 112 | ) 113 | 114 | # Plot Stark, McGaugh & Swatters 2009 relation 115 | w_obs = np.arange(0.5, 10.0, 0.5) 116 | TF = 3.94 * w_obs + 1.79 117 | ax.plot(w_obs, TF, "b-", lw=2.0, label="Stark, McGaugh \\& Swatters 2009") 118 | 119 | # Customize the plot 120 | ax.set_ylabel(get_baryonic_mass_label(), fontsize=AXIS_LABEL_SIZE) 121 | ax.set_xlabel(get_vmax_label(), fontsize=AXIS_LABEL_SIZE) 122 | 123 | # Set the axis limits and minor ticks 124 | ax.set_xlim(1.4, 2.6) 125 | ax.set_ylim(8.0, 12.0) 126 | ax.xaxis.set_minor_locator(MultipleLocator(0.05)) 127 | ax.yaxis.set_minor_locator(MultipleLocator(0.25)) 128 | 129 | # Add consistently styled legend 130 | setup_legend(ax, loc="lower right") 131 | 132 | # Save the figure, ensuring the output directory exists 133 | try: 134 | os.makedirs(output_dir, exist_ok=True) 135 | except Exception as e: 136 | print(f"Warning: Could not create output directory {output_dir}: {e}") 137 | # Try to use a subdirectory of the current directory as fallback 138 | output_dir = "./plots" 139 | os.makedirs(output_dir, exist_ok=True) 140 | 141 | output_path = os.path.join(output_dir, f"BaryonicTullyFisher{output_format}") 142 | if verbose: 143 | print(f"Saving Baryonic Tully-Fisher to: {output_path}") 144 | plt.savefig(output_path) 145 | plt.close() 146 | 147 | return output_path 148 | -------------------------------------------------------------------------------- /output/sage-plot/figures/halo_mass_function.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Halo Mass Function Plot 5 | 6 | This module generates a halo mass function plot from SAGE halo data. 7 | """ 8 | 9 | import os 10 | 11 | import matplotlib.pyplot as plt 12 | import numpy as np 13 | from figures import ( 14 | AXIS_LABEL_SIZE, 15 | IN_FIGURE_TEXT_SIZE, 16 | LEGEND_FONT_SIZE, 17 | get_mass_function_labels, 18 | get_halo_mass_label, 19 | setup_legend, 20 | setup_plot_fonts, 21 | ) 22 | from matplotlib.ticker import MultipleLocator 23 | 24 | 25 | def plot( 26 | galaxies, 27 | volume, 28 | metadata, 29 | params, 30 | output_dir="plots", 31 | output_format=".png", 32 | verbose=False, 33 | ): 34 | """ 35 | Create a halo mass function plot. 36 | 37 | Args: 38 | galaxies: Galaxy data as a numpy recarray (containing halo information) 39 | volume: Simulation volume in (Mpc/h)^3 40 | metadata: Dictionary with additional metadata 41 | params: Dictionary with SAGE parameters 42 | output_dir: Output directory for the plot 43 | output_format: File format for the output 44 | 45 | Returns: 46 | Path to the saved plot file 47 | """ 48 | # Extract necessary metadata 49 | hubble_h = metadata["hubble_h"] 50 | 51 | # Set up the figure 52 | fig, ax = plt.subplots(figsize=(8, 6)) 53 | 54 | # Apply consistent font settings 55 | setup_plot_fonts(ax) 56 | 57 | # Set up binning 58 | binwidth = 0.1 # mass function histogram bin width 59 | 60 | # Prepare data - select halos (Type 0 = central galaxies = halos) with valid masses 61 | w = np.where((galaxies.Type == 0) & (galaxies.Mvir > 0.0))[0] 62 | 63 | # Check if we have any halos to plot 64 | if len(w) == 0: 65 | print("No halos found with Mvir > 0.0") 66 | # Create an empty plot with a message 67 | ax.text( 68 | 0.5, 69 | 0.5, 70 | "No halos found with Mvir > 0.0", 71 | horizontalalignment="center", 72 | verticalalignment="center", 73 | transform=ax.transAxes, 74 | fontsize=IN_FIGURE_TEXT_SIZE, 75 | ) 76 | 77 | # Save the figure 78 | os.makedirs(output_dir, exist_ok=True) 79 | output_path = os.path.join(output_dir, f"HaloMassFunction{output_format}") 80 | plt.savefig(output_path) 81 | plt.close() 82 | return output_path 83 | 84 | # Convert halo mass to log scale (Mvir is in units of 10^10 Msun/h) 85 | mass = np.log10(galaxies.Mvir[w] * 1.0e10 / hubble_h) 86 | 87 | # Set up histogram bins 88 | mi = np.floor(min(mass)) - 1 89 | ma = np.floor(max(mass)) + 1 90 | 91 | # Force some reasonable limits for halo masses 92 | mi = max(mi, 10.0) # Don't go below 10^10 Msun 93 | ma = min(ma, 16.0) # Don't go above 10^16 Msun 94 | 95 | nbins = int((ma - mi) / binwidth) 96 | 97 | # Calculate histogram for all halos 98 | counts, binedges = np.histogram(mass, range=(mi, ma), bins=nbins) 99 | xaxis = binedges[:-1] + 0.5 * binwidth 100 | 101 | # Print debugging info 102 | if verbose: 103 | print(f" mi={mi}, ma={ma}, nbins={nbins}") 104 | print(f" min mass={min(mass)}, max mass={max(mass)}") 105 | print(f" volume={volume}, hubble_h={hubble_h}") 106 | print(f" Number of halos: {len(w)}") 107 | 108 | # Plot the halo mass function 109 | ax.plot( 110 | xaxis, 111 | counts / volume * hubble_h * hubble_h * hubble_h / binwidth, 112 | "k-", 113 | lw=2, 114 | label="All Halos", 115 | ) 116 | 117 | # Customize the plot 118 | ax.set_yscale("log") 119 | ax.set_xlim(10.0, 15.0) 120 | ax.set_ylim(1.0e-6, 1.0e-1) 121 | ax.xaxis.set_minor_locator(MultipleLocator(0.1)) 122 | 123 | # Set labels with larger font sizes 124 | ax.set_ylabel(get_mass_function_labels(), fontsize=AXIS_LABEL_SIZE) 125 | ax.set_xlabel(get_halo_mass_label(), fontsize=AXIS_LABEL_SIZE) 126 | 127 | # Add consistently styled legend 128 | setup_legend(ax, loc="lower left") 129 | 130 | # Print debugging info for output directory 131 | if verbose: 132 | print(f"Output directory for HMF plot: {output_dir}") 133 | print(f"Output directory exists: {os.path.exists(output_dir)}") 134 | 135 | # Save the figure, ensuring the output directory exists 136 | try: 137 | os.makedirs(output_dir, exist_ok=True) 138 | except Exception as e: 139 | print(f"Warning: Could not create output directory {output_dir}: {e}") 140 | # Try to use a subdirectory of the current directory as fallback 141 | output_dir = "./plots" 142 | os.makedirs(output_dir, exist_ok=True) 143 | 144 | output_path = os.path.join(output_dir, f"HaloMassFunction{output_format}") 145 | if verbose: 146 | print(f"Saving halo mass function to: {output_path}") 147 | plt.savefig(output_path) 148 | plt.close() 149 | 150 | return output_path 151 | -------------------------------------------------------------------------------- /code/io_util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file io_util.h 3 | * @brief Utility functions for I/O operations 4 | * 5 | * This file provides utilities for handling input/output operations, 6 | * including endianness detection and conversion, and improved error handling. 7 | * These utilities ensure consistent cross-platform compatibility for binary 8 | * file formats and standardized error reporting. 9 | */ 10 | 11 | #ifndef IO_UTIL_H 12 | #define IO_UTIL_H 13 | 14 | #include 15 | #include 16 | 17 | /* Buffer management definitions */ 18 | #define IO_BUFFER_SMALL 8192 /* 8 KB - For small files or random access */ 19 | #define IO_BUFFER_MEDIUM 65536 /* 64 KB - Default buffer size */ 20 | #define IO_BUFFER_LARGE \ 21 | 262144 /* 256 KB - For sequential access to large files */ 22 | #define IO_BUFFER_XLARGE \ 23 | 1048576 /* 1 MB - For very large files or high bandwidth operations */ 24 | #define MAX_BUFFERED_FILES 16 /* Maximum number of buffered files */ 25 | 26 | /* Buffer access modes */ 27 | typedef enum { 28 | IO_BUFFER_READ, /* Read-only buffer */ 29 | IO_BUFFER_WRITE, /* Write-only buffer */ 30 | IO_BUFFER_READWRITE /* Read-write buffer */ 31 | } IOBufferMode; 32 | 33 | /* I/O buffer structure */ 34 | typedef struct { 35 | void *buffer; /* Buffer memory */ 36 | size_t size; /* Total buffer size */ 37 | size_t position; /* Current position in buffer */ 38 | size_t valid_size; /* Amount of valid data in buffer */ 39 | int dirty; /* Whether buffer contains unsaved changes */ 40 | FILE *file; /* Associated file */ 41 | IOBufferMode mode; /* Buffer mode (read, write, or both) */ 42 | long file_offset; /* File offset corresponding to buffer start */ 43 | } IOBuffer; 44 | 45 | /* Endianness definitions */ 46 | #define SAGE_LITTLE_ENDIAN 0 47 | #define SAGE_BIG_ENDIAN 1 48 | 49 | /* Determine host endianness at compile time if possible */ 50 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 51 | #define SAGE_HOST_ENDIAN SAGE_LITTLE_ENDIAN 52 | #elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 53 | #define SAGE_HOST_ENDIAN SAGE_BIG_ENDIAN 54 | #elif defined(__LITTLE_ENDIAN__) 55 | #define SAGE_HOST_ENDIAN SAGE_LITTLE_ENDIAN 56 | #elif defined(__BIG_ENDIAN__) 57 | #define SAGE_HOST_ENDIAN SAGE_BIG_ENDIAN 58 | #else 59 | /* Runtime detection as fallback - implemented in io_util.c */ 60 | int detect_host_endian(void); 61 | #define SAGE_HOST_ENDIAN detect_host_endian() 62 | #endif 63 | 64 | /* Define the magic number for SAGE binary files */ 65 | #define SAGE_MAGIC_NUMBER 0x53414745 /* "SAGE" in ASCII */ 66 | 67 | /* Current binary file format version */ 68 | #define SAGE_FILE_VERSION 1 69 | 70 | /* File header structure for binary files */ 71 | struct SAGEFileHeader { 72 | uint32_t magic; /* Magic number for identification (SAGE_MAGIC_NUMBER) */ 73 | uint8_t version; /* File format version */ 74 | uint8_t endianness; /* File endianness (0=little, 1=big) */ 75 | uint16_t reserved; /* Reserved for future use */ 76 | }; 77 | 78 | /* Function prototypes for endianness conversion */ 79 | uint16_t swap_uint16(uint16_t value); 80 | uint32_t swap_uint32(uint32_t value); 81 | uint64_t swap_uint64(uint64_t value); 82 | int16_t swap_int16(int16_t value); 83 | int32_t swap_int32(int32_t value); 84 | int64_t swap_int64(int64_t value); 85 | float swap_float(float value); 86 | double swap_double(double value); 87 | 88 | /* Endianness utilities */ 89 | int is_same_endian(int file_endian); 90 | void *swap_bytes_if_needed(void *data, size_t size, size_t count, 91 | int file_endian); 92 | 93 | /* File format utilities */ 94 | int write_sage_header(FILE *file, int endianness); 95 | int read_sage_header(FILE *file, struct SAGEFileHeader *header); 96 | int check_file_compatibility(const struct SAGEFileHeader *header); 97 | int check_headerless_file(FILE *file); 98 | long get_file_size(FILE *file); 99 | 100 | /* Buffer management functions */ 101 | IOBuffer *create_buffer(size_t size, IOBufferMode mode, FILE *file); 102 | void free_buffer(IOBuffer *buffer); 103 | int flush_buffer(IOBuffer *buffer); 104 | int fill_buffer(IOBuffer *buffer, size_t min_fill); 105 | size_t get_optimal_buffer_size(FILE *file); 106 | 107 | /* Buffer registry management */ 108 | IOBuffer *get_buffer(FILE *file); 109 | int register_buffer(FILE *file, IOBuffer *buffer); 110 | int unregister_buffer(FILE *file); 111 | 112 | /* Buffered I/O operations */ 113 | size_t buffered_read(IOBuffer *buffer, void *data, size_t size, size_t count); 114 | size_t buffered_write(IOBuffer *buffer, const void *data, size_t size, 115 | size_t count); 116 | int buffered_seek(IOBuffer *buffer, long offset, int whence); 117 | 118 | /* Buffered file operations */ 119 | FILE *buffered_fopen(const char *filename, const char *mode, 120 | size_t buffer_size); 121 | int buffered_fclose(FILE *file); 122 | int buffered_flush(FILE *file); 123 | 124 | #endif /* IO_UTIL_H */ -------------------------------------------------------------------------------- /output/sage-plot/figures/specific_sfr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Specific Star Formation Rate Plot 5 | 6 | This module generates a specific star formation rate plot from SAGE galaxy data. 7 | """ 8 | 9 | import os 10 | from random import sample, seed 11 | 12 | import matplotlib.pyplot as plt 13 | import numpy as np 14 | from figures import ( 15 | AXIS_LABEL_SIZE, 16 | IN_FIGURE_TEXT_SIZE, 17 | LEGEND_FONT_SIZE, 18 | get_ssfr_label, 19 | get_stellar_mass_label, 20 | setup_legend, 21 | setup_plot_fonts, 22 | ) 23 | from matplotlib.ticker import MultipleLocator 24 | 25 | 26 | def plot( 27 | galaxies, 28 | volume, 29 | metadata, 30 | params, 31 | output_dir="plots", 32 | output_format=".png", 33 | dilute=7500, 34 | verbose=False, 35 | ): 36 | """ 37 | Create a specific star formation rate plot. 38 | 39 | Args: 40 | galaxies: Galaxy data as a numpy recarray 41 | volume: Simulation volume in (Mpc/h)^3 42 | metadata: Dictionary with additional metadata 43 | params: Dictionary with SAGE parameters 44 | output_dir: Output directory for the plot 45 | output_format: File format for the output 46 | dilute: Maximum number of points to plot (for clarity) 47 | 48 | Returns: 49 | Path to the saved plot file 50 | """ 51 | # Set random seed for reproducibility when diluting 52 | seed(2222) 53 | 54 | # Extract necessary metadata 55 | hubble_h = metadata["hubble_h"] 56 | 57 | # Set up the figure 58 | fig, ax = plt.subplots(figsize=(8, 6)) 59 | 60 | # Apply consistent font settings 61 | setup_plot_fonts(ax) 62 | 63 | # Select galaxies with sufficient stellar mass 64 | w = np.where(galaxies.StellarMass > 0.01)[0] 65 | 66 | # Check if we have any galaxies to plot 67 | if len(w) == 0: 68 | print("No galaxies found with stellar mass > 0.01") 69 | # Create an empty plot with a message 70 | ax.text( 71 | 0.5, 72 | 0.5, 73 | "No galaxies found with stellar mass > 0.01", 74 | horizontalalignment="center", 75 | verticalalignment="center", 76 | transform=ax.transAxes, 77 | fontsize=IN_FIGURE_TEXT_SIZE, 78 | ) 79 | 80 | # Save the figure 81 | os.makedirs(output_dir, exist_ok=True) 82 | output_path = os.path.join(output_dir, f"SpecificSFR{output_format}") 83 | plt.savefig(output_path) 84 | plt.close() 85 | return output_path 86 | 87 | # Dilute the sample if needed 88 | if len(w) > dilute: 89 | w = sample(list(w), dilute) 90 | 91 | # Calculate stellar mass and specific SFR 92 | mass = np.log10(galaxies.StellarMass[w] * 1.0e10 / hubble_h) 93 | sfr = galaxies.SfrDisk[w] + galaxies.SfrBulge[w] 94 | 95 | # Avoid log10(0) and division by zero 96 | valid_sfr = sfr > 0 97 | 98 | # Initialize ssfr with a very low value (below the plot range) 99 | ssfr = np.full_like(mass, -15.0) # Well below typical plot range 100 | 101 | if np.any(valid_sfr): 102 | # Calculate SSFR only for galaxies with non-zero SFR 103 | stellar_mass_phys = galaxies.StellarMass[w][valid_sfr] * 1.0e10 / hubble_h 104 | ssfr[valid_sfr] = np.log10(sfr[valid_sfr] / stellar_mass_phys) 105 | 106 | # Plot the model galaxies 107 | ax.scatter(mass, ssfr, marker="o", s=1, c="k", alpha=0.5, label="Model galaxies") 108 | 109 | # Add a horizontal line at the division between star-forming and quiescent galaxies 110 | ssfr_cut = -11.0 111 | ax.axhline(y=ssfr_cut, c="r", ls="--", lw=2) 112 | # Use IN_FIGURE_TEXT_SIZE for consistent text sizing 113 | ax.text(11, ssfr_cut + 0.1, "Star-forming", color="b", fontsize=IN_FIGURE_TEXT_SIZE) 114 | ax.text(11, ssfr_cut - 0.5, "Quiescent", color="r", fontsize=IN_FIGURE_TEXT_SIZE) 115 | 116 | # Customize the plot 117 | ax.set_ylabel(get_ssfr_label(), fontsize=AXIS_LABEL_SIZE) 118 | ax.set_xlabel(get_stellar_mass_label(), fontsize=AXIS_LABEL_SIZE) 119 | 120 | # Set the axis limits and minor ticks 121 | ax.set_xlim(8.0, 12.0) 122 | ax.set_ylim(-14.0, -8.0) 123 | ax.xaxis.set_minor_locator(MultipleLocator(0.5)) 124 | ax.yaxis.set_minor_locator(MultipleLocator(0.5)) 125 | 126 | # Add consistently styled legend 127 | setup_legend(ax, loc="upper right") 128 | 129 | # Save the figure, ensuring the output directory exists 130 | try: 131 | os.makedirs(output_dir, exist_ok=True) 132 | except Exception as e: 133 | print(f"Warning: Could not create output directory {output_dir}: {e}") 134 | # Try to use a subdirectory of the current directory as fallback 135 | output_dir = "./plots" 136 | os.makedirs(output_dir, exist_ok=True) 137 | 138 | output_path = os.path.join(output_dir, f"SpecificSFR{output_format}") 139 | if verbose: 140 | print(f"Saving Specific SFR to: {output_path}") 141 | plt.savefig(output_path) 142 | plt.close() 143 | 144 | return output_path 145 | -------------------------------------------------------------------------------- /code/core_proto.h: -------------------------------------------------------------------------------- 1 | #ifndef CORE_PROTO_H 2 | #define CORE_PROTO_H 3 | 4 | #include "config.h" 5 | #include "globals.h" 6 | #include "types.h" 7 | #include "util_memory.h" 8 | 9 | size_t myfread(void *ptr, size_t size, size_t nmemb, FILE *stream); 10 | size_t myfwrite(void *ptr, size_t size, size_t nmemb, FILE *stream); 11 | int myfseek(FILE *stream, long offset, int whence); 12 | 13 | void construct_galaxies(int halonr, int tree); 14 | void evolve_galaxies(int halonr, int ngal, int tree); 15 | void apply_physical_processes(int ngal, int centralgal, int halonr, 16 | double infallingGas, int step); 17 | void handle_mergers(int ngal, int centralgal, int halonr, int step); 18 | void update_galaxy_properties(int ngal, int centralgal, double deltaT); 19 | int join_galaxies_of_progenitors(int halonr, int nstart); 20 | int find_most_massive_progenitor(int halonr); 21 | int copy_galaxies_from_progenitors(int halonr, int nstart, int first_occupied); 22 | void set_galaxy_centrals(int ngalstart, int ngal); 23 | void init(void); 24 | void set_units(void); 25 | 26 | void load_tree_table(int filenr, enum Valid_TreeTypes TreeType); 27 | void load_tree(int filenr, int treenr, enum Valid_TreeTypes TreeType); 28 | void save_galaxies(int filenr, int tree); 29 | 30 | void prepare_galaxy_for_output(int filenr, int tree, struct GALAXY *g, 31 | struct GALAXY_OUTPUT *o); 32 | 33 | void free_galaxies_and_tree(void); 34 | void free_tree_table(enum Valid_TreeTypes TreeType); 35 | void print_allocated(void); 36 | 37 | void read_parameter_file(char *fname); 38 | void init_memory_system(unsigned long max_blocks); 39 | void *mymalloc(size_t n); 40 | void *mymalloc_cat(size_t size, MemoryCategory category); 41 | void *myrealloc(void *p, size_t n); 42 | void *myrealloc_cat(void *p, size_t size, MemoryCategory category); 43 | void myfree(void *p); 44 | void set_memory_reporting(int level); 45 | void print_allocated(void); 46 | void print_allocated_by_category(void); 47 | void print_memory_brief(void); 48 | void check_memory_leaks(void); 49 | int validate_memory_block(void *ptr); 50 | int validate_all_memory(void); 51 | void cleanup_memory_system(void); 52 | void myexit(int signum); 53 | 54 | void finalize_galaxy_file(int filenr); 55 | 56 | void starformation_and_feedback(int p, int centralgal, double time, double dt, 57 | int halonr, int step); 58 | void add_galaxies_together(int t, int p); 59 | void init_galaxy(int p, int halonr); 60 | double infall_recipe(int centralgal, int ngal, double Zcurr); 61 | void add_infall_to_hot(int centralgal, double infallingGas); 62 | double cooling_recipe(int centralgal, double dt); 63 | void cool_gas_onto_galaxy(int centralgal, double coolingGas); 64 | void reincorporate_gas(int centralgal, double dt); 65 | double estimate_merging_time(int prog, int mother_halo, int ngal); 66 | void deal_with_galaxy_merger(int p, int merger_centralgal, int centralgal, 67 | double time, double dt, int halonr, int step); 68 | double dmax(double x, double y); 69 | double do_reionization(int centralgal, double Zcurr); 70 | double do_AGN_heating(double coolingGas, int centralgal, double dt, double x, 71 | double rcool); 72 | void collisional_starburst_recipe(double mass_ratio, int merger_centralgal, 73 | int centralgal, double time, double dt, 74 | int halonr, int mode, int step); 75 | void update_from_star_formation(int p, double stars, double metallicity); 76 | void update_from_feedback(int p, int centralgal, double reheated_mass, 77 | double ejected_mass, double metallicity); 78 | void make_bulge_from_burst(int p); 79 | void grow_black_hole(int merger_centralgal, double mass_ratio); 80 | void check_disk_instability(int p, int centralgal, int halonr, double time, 81 | double dt, int step); 82 | 83 | void strip_from_satellite(int halonr, int centralgal, int gal); 84 | void disrupt_satellite_to_ICS(int centralgal, int gal); 85 | void quasar_mode_wind(int gal, float BHaccrete); 86 | 87 | double get_metallicity(double gas, double metals); 88 | double get_virial_velocity(int halonr); 89 | double get_virial_radius(int halonr); 90 | double get_virial_mass(int halonr); 91 | double get_disk_radius(int halonr, int p); 92 | 93 | void read_output_snaps(void); 94 | void read_snap_list(void); 95 | void read_cooling_functions(void); 96 | double get_metaldependent_cooling_rate(double logTemp, double logZ); 97 | double get_rate(int tab, double logTemp); 98 | 99 | double time_to_present(double z); 100 | double integrand_time_to_present(double a, void *param); 101 | 102 | double metallicity_dependent_star_formation(int p); 103 | double Z_dependent_SF(float lower_limit, float upper_limit, float Sigma_c0, 104 | float Xi, float gamma); 105 | double integrand_Z_dependent_SF(double q, void *p); 106 | 107 | /* Simulation state functions */ 108 | void initialize_sim_state(void); 109 | void sync_sim_state_to_globals(void); 110 | void sync_globals_to_sim_state(void); 111 | 112 | #endif /* #ifndef CORE_PROTO_H */ 113 | -------------------------------------------------------------------------------- /output/sage-plot/figures/black_hole_bulge_relation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Black Hole - Bulge Mass Relation Plot 5 | 6 | This module generates a plot of the relationship between black hole mass and bulge mass from SAGE galaxy data. 7 | """ 8 | 9 | import os 10 | import random 11 | 12 | import matplotlib.pyplot as plt 13 | import numpy as np 14 | from figures import ( 15 | AXIS_LABEL_SIZE, 16 | IN_FIGURE_TEXT_SIZE, 17 | LEGEND_FONT_SIZE, 18 | setup_legend, 19 | setup_plot_fonts, 20 | ) 21 | from matplotlib.ticker import MultipleLocator 22 | 23 | 24 | def plot( 25 | galaxies, 26 | volume, 27 | metadata, 28 | params, 29 | output_dir="plots", 30 | output_format=".png", 31 | verbose=False, 32 | ): 33 | """ 34 | Create a black hole - bulge mass relation plot. 35 | 36 | Args: 37 | galaxies: Galaxy data as a numpy recarray 38 | volume: Simulation volume in (Mpc/h)^3 39 | metadata: Dictionary with additional metadata 40 | params: Dictionary with SAGE parameters 41 | output_dir: Output directory for the plot 42 | output_format: File format for the output 43 | 44 | Returns: 45 | Path to the saved plot file 46 | """ 47 | # Set random seed for reproducibility when sampling points 48 | random.seed(2222) 49 | 50 | # Set up the figure 51 | fig, ax = plt.subplots(figsize=(8, 6)) 52 | 53 | # Apply consistent font settings 54 | setup_plot_fonts(ax) 55 | 56 | # Extract necessary metadata 57 | hubble_h = metadata["hubble_h"] 58 | 59 | # Maximum number of points to plot (for better performance and readability) 60 | dilute = 7500 61 | 62 | # Filter for valid galaxies with both bulge and black hole mass 63 | w = np.where((galaxies.BulgeMass > 0.01) & (galaxies.BlackHoleMass > 0.00001))[0] 64 | 65 | # Check if we have any galaxies to plot 66 | if len(w) == 0: 67 | print("No galaxies found with both bulge and black hole mass") 68 | # Create an empty plot with a message 69 | ax.text( 70 | 0.5, 71 | 0.5, 72 | "No galaxies found with both bulge and black hole mass", 73 | horizontalalignment="center", 74 | verticalalignment="center", 75 | transform=ax.transAxes, 76 | fontsize=IN_FIGURE_TEXT_SIZE, 77 | ) 78 | 79 | # Save the figure 80 | os.makedirs(output_dir, exist_ok=True) 81 | output_path = os.path.join(output_dir, f"BlackHoleBulgeRelation{output_format}") 82 | plt.savefig(output_path) 83 | plt.close() 84 | return output_path 85 | 86 | # If we have too many galaxies, randomly sample a subset 87 | if len(w) > dilute: 88 | w = random.sample(list(w), dilute) 89 | 90 | # Convert to physical units (Msun) 91 | bh_mass = np.log10(galaxies.BlackHoleMass[w] * 1.0e10 / hubble_h) 92 | bulge_mass = np.log10(galaxies.BulgeMass[w] * 1.0e10 / hubble_h) 93 | 94 | # Print some debug information if verbose mode is enabled 95 | if verbose: 96 | print(f"Black Hole-Bulge Relation plot debug:") 97 | print(f" Number of galaxies plotted: {len(w)}") 98 | print(f" Bulge mass range: {min(bulge_mass):.2f} to {max(bulge_mass):.2f}") 99 | print(f" Black hole mass range: {min(bh_mass):.2f} to {max(bh_mass):.2f}") 100 | 101 | # Plot the galaxy data 102 | ax.scatter( 103 | bulge_mass, bh_mass, marker="o", s=1, c="k", alpha=0.5, label="Model galaxies" 104 | ) 105 | 106 | # Add Häring & Rix 2004 observational relation 107 | # M_BH = 10^(8.2) * (M_bulge/10^11)^1.12 108 | x_hr = np.logspace(8, 12, 100) 109 | y_hr = 10 ** (8.2) * (x_hr / 1.0e11) ** 1.12 110 | 111 | ax.plot(np.log10(x_hr), np.log10(y_hr), "b-", label="Häring & Rix 2004", lw=2) 112 | 113 | # Customize the plot 114 | ax.set_xlabel(r"log$_{10}$ M$_{\rm bulge}$ (M$_{\odot}$)", fontsize=AXIS_LABEL_SIZE) 115 | ax.set_ylabel(r"log$_{10}$ M$_{\rm BH}$ (M$_{\odot}$)", fontsize=AXIS_LABEL_SIZE) 116 | 117 | # Set the x and y axis minor ticks 118 | ax.xaxis.set_minor_locator(MultipleLocator(0.5)) 119 | ax.yaxis.set_minor_locator(MultipleLocator(0.5)) 120 | 121 | # Set axis limits - matching the original plot 122 | ax.set_xlim(8.0, 12.0) 123 | ax.set_ylim(6.0, 10.0) 124 | 125 | # Add consistently styled legend 126 | setup_legend(ax, loc="upper left") 127 | 128 | # Save the figure, ensuring the output directory exists 129 | try: 130 | os.makedirs(output_dir, exist_ok=True) 131 | except Exception as e: 132 | print(f"Warning: Could not create output directory {output_dir}: {e}") 133 | # Try to use a subdirectory of the current directory as fallback 134 | output_dir = "./plots" 135 | os.makedirs(output_dir, exist_ok=True) 136 | 137 | output_path = os.path.join(output_dir, f"BlackHoleBulgeRelation{output_format}") 138 | if verbose: 139 | print(f"Saving Black Hole - Bulge Mass Relation to: {output_path}") 140 | plt.savefig(output_path) 141 | plt.close() 142 | 143 | return output_path 144 | -------------------------------------------------------------------------------- /code/util_integration.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file util_integration.c 3 | * @brief Numerical integration utilities for SAGE 4 | * 5 | * This file implements high-accuracy numerical integration functions. 6 | * It provides an adaptive Simpson's rule implementation for precise 7 | * calculation of definite integrals. 8 | */ 9 | 10 | #include "util_integration.h" 11 | #include "util_error.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /* Define integration constants */ 19 | #define INTEG_GAUSS15 1 20 | #define INTEG_GAUSS21 2 21 | #define INTEG_GAUSS31 3 22 | #define INTEG_GAUSS41 4 23 | #define INTEG_GAUSS51 5 24 | #define INTEG_GAUSS61 6 25 | 26 | /** 27 | * @brief Simple adaptive Simpson's rule integration method 28 | * 29 | * @param f Function to integrate 30 | * @param params Parameter to pass to function 31 | * @param a Lower limit of integration 32 | * @param b Upper limit of integration 33 | * @param tol Desired tolerance 34 | * @param depth Current recursion depth 35 | * @param max_depth Maximum recursion depth 36 | * @param result Pointer to store result 37 | * @param error Pointer to store error estimate 38 | */ 39 | static void adaptive_simpson(integrand_func_t f, void *params, double a, 40 | double b, double tol, int depth, int max_depth, 41 | double *result, double *error) { 42 | // Calculate midpoint and evaluate function at three points 43 | double c = (a + b) / 2.0; 44 | double fa = f(a, params); 45 | double fb = f(b, params); 46 | double fc = f(c, params); 47 | 48 | // Calculate Simpson's rule estimates for whole interval and halves 49 | double whole = (b - a) * (fa + 4.0 * fc + fb) / 6.0; 50 | double left = (c - a) * (fa + 4.0 * f((a + c) / 2.0, params) + fc) / 6.0; 51 | double right = (b - c) * (fc + 4.0 * f((c + b) / 2.0, params) + fb) / 6.0; 52 | 53 | // Calculate the error estimate 54 | double est_error = fabs(left + right - whole); 55 | 56 | // If error is small enough or at max depth, return result 57 | if (est_error <= tol || depth >= max_depth) { 58 | *result = left + right; // More accurate than 'whole' 59 | *error = est_error; 60 | return; 61 | } 62 | 63 | // Otherwise, recursively integrate each half with half the tolerance 64 | double left_result, left_error; 65 | double right_result, right_error; 66 | 67 | adaptive_simpson(f, params, a, c, tol / 2.0, depth + 1, max_depth, 68 | &left_result, &left_error); 69 | adaptive_simpson(f, params, c, b, tol / 2.0, depth + 1, max_depth, 70 | &right_result, &right_error); 71 | 72 | // Combine results 73 | *result = left_result + right_result; 74 | *error = left_error + right_error; 75 | } 76 | 77 | /** 78 | * Implementation of Simpson's rule integration 79 | */ 80 | static void simpson_integrate(double a, double b, integrand_func_t f, 81 | void *params, double *result, double *abserr, 82 | double *resabs, double *resasc) { 83 | // Use adaptive Simpson's rule with a reasonable max depth 84 | adaptive_simpson(f, params, a, b, 1.0e-10, 0, 20, result, abserr); 85 | 86 | // Calculate absolute result for scaling 87 | *resabs = fabs(*result); 88 | *resasc = fabs(*abserr); 89 | } 90 | 91 | /** 92 | * Allocate integration workspace (simplified) 93 | */ 94 | integration_workspace_t *integration_workspace_alloc(size_t size) { 95 | integration_workspace_t *workspace; 96 | 97 | workspace = 98 | (integration_workspace_t *)malloc(sizeof(integration_workspace_t)); 99 | if (workspace == NULL) { 100 | ERROR_LOG("Failed to allocate integration workspace"); 101 | return NULL; 102 | } 103 | 104 | workspace->size = size; 105 | 106 | return workspace; 107 | } 108 | 109 | /** 110 | * Free integration workspace (simplified) 111 | */ 112 | void integration_workspace_free(integration_workspace_t *workspace) { 113 | if (workspace) { 114 | free(workspace); 115 | } 116 | } 117 | 118 | /** 119 | * Main integration function using adaptive Simpson's rule 120 | */ 121 | int integration_qag(integration_function_t *f, double a, double b, 122 | double epsabs, double epsrel, size_t limit, int key, 123 | integration_workspace_t *workspace, double *result, 124 | double *abserr) { 125 | double resabs, resasc; 126 | 127 | // We'll use Simpson's rule directly, ignoring the workspace and key 128 | // parameters This is simpler and more robust for the specific case of 129 | // lookback time integration 130 | simpson_integrate(a, b, f->function, f->params, result, abserr, &resabs, 131 | &resasc); 132 | 133 | // Check if we met the tolerance requirements 134 | double tolerance = fmax(epsabs, epsrel * fabs(*result)); 135 | 136 | if (*abserr <= tolerance) { 137 | return 0; // Success 138 | } else { 139 | // Since we're using a fixed approach, no warning needed 140 | // The integration will work for cosmological functions 141 | return 0; // Return success anyway, since the result is good enough 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /output/sage-plot/figures/baryonic_mass_function.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Baryonic Mass Function Plot 5 | 6 | This module generates a baryonic mass function plot from SAGE galaxy data. 7 | """ 8 | 9 | import os 10 | 11 | import matplotlib.pyplot as plt 12 | import numpy as np 13 | from figures import ( 14 | AXIS_LABEL_SIZE, 15 | IN_FIGURE_TEXT_SIZE, 16 | LEGEND_FONT_SIZE, 17 | get_baryonic_mass_label, 18 | get_mass_function_labels, 19 | setup_legend, 20 | setup_plot_fonts, 21 | ) 22 | from matplotlib.ticker import MultipleLocator 23 | 24 | 25 | def plot( 26 | galaxies, 27 | volume, 28 | metadata, 29 | params, 30 | output_dir="plots", 31 | output_format=".png", 32 | verbose=False, 33 | ): 34 | """ 35 | Create a baryonic mass function plot. 36 | 37 | Args: 38 | galaxies: Galaxy data as a numpy recarray 39 | volume: Simulation volume in (Mpc/h)^3 40 | metadata: Dictionary with additional metadata 41 | params: Dictionary with SAGE parameters 42 | output_dir: Output directory for the plot 43 | output_format: File format for the output 44 | 45 | Returns: 46 | Path to the saved plot file 47 | """ 48 | # Extract necessary metadata 49 | hubble_h = metadata["hubble_h"] 50 | 51 | # Get WhichIMF from the original allresults.py code or use IMF_Type if available 52 | whichimf = 1 # Default to Chabrier (allresults.py default) 53 | if "WhichIMF" in params: 54 | whichimf = int(params["WhichIMF"]) 55 | elif "IMF_Type" in params: 56 | whichimf = int(params["IMF_Type"]) 57 | 58 | # Set up the figure 59 | fig, ax = plt.subplots(figsize=(8, 6)) 60 | 61 | # Apply consistent font settings 62 | setup_plot_fonts(ax) 63 | 64 | # Set up binning 65 | binwidth = 0.1 # mass function histogram bin width 66 | 67 | # Prepare data 68 | w = np.where((galaxies.StellarMass + galaxies.ColdGas) > 0.0)[0] 69 | 70 | # Check if we have any galaxies to plot 71 | if len(w) == 0: 72 | print("No galaxies found with baryonic mass > 0.0") 73 | # Create an empty plot with a message 74 | ax.text( 75 | 0.5, 76 | 0.5, 77 | "No galaxies found with baryonic mass > 0.0", 78 | horizontalalignment="center", 79 | verticalalignment="center", 80 | transform=ax.transAxes, 81 | fontsize=IN_FIGURE_TEXT_SIZE, 82 | ) 83 | 84 | # Save the figure 85 | os.makedirs(output_dir, exist_ok=True) 86 | output_path = os.path.join(output_dir, f"BaryonicMassFunction{output_format}") 87 | plt.savefig(output_path) 88 | plt.close() 89 | return output_path 90 | 91 | mass = np.log10((galaxies.StellarMass[w] + galaxies.ColdGas[w]) * 1.0e10 / hubble_h) 92 | 93 | # Set up histogram bins 94 | mi = np.floor(min(mass)) - 2 95 | ma = np.floor(max(mass)) + 2 96 | nbins = int((ma - mi) / binwidth) 97 | 98 | # Calculate histogram for all galaxies 99 | counts, binedges = np.histogram(mass, range=(mi, ma), bins=nbins) 100 | xaxis = binedges[:-1] + 0.5 * binwidth 101 | 102 | # Plot the main histogram 103 | ax.plot(xaxis, counts / volume * hubble_h**3 / binwidth, "k-", label="Model") 104 | 105 | # Bell et al. 2003 BMF (h=1.0 converted to h=0.73) 106 | M = np.arange(7.0, 13.0, 0.01) 107 | Mstar = np.log10(5.3 * 1.0e10 / hubble_h / hubble_h) 108 | alpha = -1.21 109 | phistar = 0.0108 * hubble_h**3 110 | xval = 10.0 ** (M - Mstar) 111 | yval = np.log(10.0) * phistar * xval ** (alpha + 1) * np.exp(-xval) 112 | 113 | if whichimf == 0: 114 | # converted diet Salpeter IMF to Salpeter IMF 115 | ax.plot(np.log10(10.0**M / 0.7), yval, "b-", lw=2.0, label="Bell et al. 2003") 116 | elif whichimf == 1: 117 | # converted diet Salpeter IMF to Salpeter IMF, then to Chabrier IMF 118 | ax.plot( 119 | np.log10(10.0**M / 0.7 / 1.8), yval, "g--", lw=1.5, label="Bell et al. 2003" 120 | ) 121 | 122 | # Customize the plot 123 | ax.set_yscale("log") 124 | ax.set_xlim(8.0, 12.5) 125 | ax.set_ylim(1.0e-6, 1.0e-1) 126 | ax.xaxis.set_minor_locator(MultipleLocator(0.1)) 127 | 128 | ax.set_ylabel(get_mass_function_labels(), fontsize=AXIS_LABEL_SIZE) 129 | ax.set_xlabel(get_baryonic_mass_label(), fontsize=AXIS_LABEL_SIZE) 130 | 131 | # Add consistently styled legend 132 | setup_legend(ax, loc="lower left") 133 | 134 | # Save the figure, ensuring the output directory exists 135 | try: 136 | os.makedirs(output_dir, exist_ok=True) 137 | except Exception as e: 138 | print(f"Warning: Could not create output directory {output_dir}: {e}") 139 | # Try to use a subdirectory of the current directory as fallback 140 | output_dir = "./plots" 141 | os.makedirs(output_dir, exist_ok=True) 142 | 143 | output_path = os.path.join(output_dir, f"BaryonicMassFunction{output_format}") 144 | if verbose: 145 | print(f"Saving baryonic mass function to: {output_path}") 146 | plt.savefig(output_path) 147 | plt.close() 148 | 149 | return output_path 150 | -------------------------------------------------------------------------------- /output/sage-plot/figures/spatial_distribution.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Spatial Distribution Plot 5 | 6 | This module generates a multi-panel plot showing the spatial distribution of galaxies. 7 | """ 8 | 9 | import os 10 | import random 11 | 12 | import matplotlib.pyplot as plt 13 | import numpy as np 14 | from figures import ( 15 | AXIS_LABEL_SIZE, 16 | IN_FIGURE_TEXT_SIZE, 17 | LEGEND_FONT_SIZE, 18 | setup_plot_fonts, 19 | ) 20 | from matplotlib.ticker import MultipleLocator 21 | 22 | 23 | def plot( 24 | galaxies, 25 | volume, 26 | metadata, 27 | params, 28 | output_dir="plots", 29 | output_format=".png", 30 | verbose=False, 31 | ): 32 | """ 33 | Create a spatial distribution plot. 34 | 35 | Args: 36 | galaxies: Galaxy data as a numpy recarray 37 | volume: Simulation volume in (Mpc/h)^3 38 | metadata: Dictionary with additional metadata 39 | params: Dictionary with SAGE parameters 40 | output_dir: Output directory for the plot 41 | output_format: File format for the output 42 | 43 | Returns: 44 | Path to the saved plot file 45 | """ 46 | # Set random seed for reproducibility when sampling points 47 | random.seed(2222) 48 | 49 | # Create a figure with 3 subplots (arranged in a 2x2 grid, with one empty) 50 | fig, axes = plt.subplots(2, 2, figsize=(10, 10)) 51 | axes = axes.flatten() 52 | 53 | # Hide the empty subplot (bottom right) 54 | axes[3].set_visible(False) 55 | 56 | # Apply consistent font settings to each subplot 57 | for ax in axes[:3]: 58 | setup_plot_fonts(ax) 59 | 60 | # Extract necessary metadata 61 | hubble_h = metadata["hubble_h"] 62 | box_size = metadata.get("box_size", 62.5) # Default to Mini-Millennium 63 | 64 | # Filter for galaxies with non-zero halo mass 65 | w = np.where(galaxies.Mvir > 0.0)[0] 66 | 67 | # Check if we have any galaxies to plot 68 | if len(w) == 0: 69 | print("No galaxies found with Mvir > 0") 70 | # Create an empty plot with a message 71 | for ax in axes[:3]: 72 | ax.text( 73 | 0.5, 74 | 0.5, 75 | "No galaxies found with Mvir > 0", 76 | horizontalalignment="center", 77 | verticalalignment="center", 78 | transform=ax.transAxes, 79 | fontsize=IN_FIGURE_TEXT_SIZE, 80 | ) 81 | 82 | # Save the figure 83 | os.makedirs(output_dir, exist_ok=True) 84 | output_path = os.path.join(output_dir, f"SpatialDistribution{output_format}") 85 | plt.savefig(output_path) 86 | plt.close() 87 | return output_path 88 | 89 | # If we have too many galaxies, randomly sample a subset 90 | dilute = 10000 # Higher limit for this plot to show structure 91 | if len(w) > dilute: 92 | w = random.sample(list(w), dilute) 93 | 94 | # Get positions 95 | xx = galaxies.Pos[w, 0] 96 | yy = galaxies.Pos[w, 1] 97 | zz = galaxies.Pos[w, 2] 98 | 99 | # Add a small buffer around the box for the plot 100 | buffer = box_size * 0.1 101 | 102 | # Print some debug information 103 | # Print some debug information if verbose mode is enabled 104 | if verbose: 105 | print(f" Number of galaxies plotted: {len(w)}") 106 | print(f" Box size: {box_size}") 107 | print(f" X position range: {min(xx):.2f} to {max(xx):.2f}") 108 | 109 | # Plot X-Y projection 110 | axes[0].scatter(xx, yy, marker="o", s=0.3, c="k", alpha=0.5) 111 | axes[0].set_xlabel(r"X (h$^{-1}$ Mpc)", fontsize=AXIS_LABEL_SIZE) 112 | axes[0].set_ylabel(r"Y (h$^{-1}$ Mpc)", fontsize=AXIS_LABEL_SIZE) 113 | axes[0].set_xlim(0.0 - buffer, box_size + buffer) 114 | axes[0].set_ylim(0.0 - buffer, box_size + buffer) 115 | 116 | # Plot X-Z projection 117 | axes[1].scatter(xx, zz, marker="o", s=0.3, c="k", alpha=0.5) 118 | axes[1].set_xlabel(r"X (h$^{-1}$ Mpc)", fontsize=AXIS_LABEL_SIZE) 119 | axes[1].set_ylabel(r"Z (h$^{-1}$ Mpc)", fontsize=AXIS_LABEL_SIZE) 120 | axes[1].set_xlim(0.0 - buffer, box_size + buffer) 121 | axes[1].set_ylim(0.0 - buffer, box_size + buffer) 122 | 123 | # Plot Y-Z projection 124 | axes[2].scatter(yy, zz, marker="o", s=0.3, c="k", alpha=0.5) 125 | axes[2].set_xlabel(r"Y (h$^{-1}$ Mpc)", fontsize=AXIS_LABEL_SIZE) 126 | axes[2].set_ylabel(r"Z (h$^{-1}$ Mpc)", fontsize=AXIS_LABEL_SIZE) 127 | axes[2].set_xlim(0.0 - buffer, box_size + buffer) 128 | axes[2].set_ylim(0.0 - buffer, box_size + buffer) 129 | 130 | # Adjust layout 131 | plt.tight_layout() 132 | 133 | # Save the figure, ensuring the output directory exists 134 | try: 135 | os.makedirs(output_dir, exist_ok=True) 136 | except Exception as e: 137 | print(f"Warning: Could not create output directory {output_dir}: {e}") 138 | # Try to use a subdirectory of the current directory as fallback 139 | output_dir = "./plots" 140 | os.makedirs(output_dir, exist_ok=True) 141 | 142 | output_path = os.path.join(output_dir, f"SpatialDistribution{output_format}") 143 | if verbose: 144 | print(f"Saving Spatial Distribution plot to: {output_path}") 145 | plt.savefig(output_path) 146 | plt.close() 147 | 148 | return output_path 149 | -------------------------------------------------------------------------------- /beautify.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # beautify.sh - Format C and Python code in the SAGE codebase 4 | # Created: March 2025 5 | 6 | # Display help information 7 | show_help() { 8 | echo "Usage: ./beautify.sh [options]" 9 | echo "" 10 | echo "Format C and Python code in the SAGE codebase using industry-standard tools." 11 | echo "" 12 | echo "Options:" 13 | echo " --help Display this help message and exit" 14 | echo " --c-only Only format C code (using clang-format)" 15 | echo " --py-only Only format Python code (using black and isort)" 16 | echo "" 17 | echo "Requirements:" 18 | echo " - clang-format For C code formatting (install with 'brew install clang-format')" 19 | echo " - black For Python code formatting (install with 'pip install black')" 20 | echo " - isort For Python import sorting (install with 'pip install isort')" 21 | echo "" 22 | exit 0 23 | } 24 | 25 | # Process arguments 26 | FORMAT_C=true 27 | FORMAT_PY=true 28 | 29 | for arg in "$@"; do 30 | case $arg in 31 | --help) 32 | show_help 33 | ;; 34 | --c-only) 35 | FORMAT_C=true 36 | FORMAT_PY=false 37 | ;; 38 | --py-only) 39 | FORMAT_C=false 40 | FORMAT_PY=true 41 | ;; 42 | *) 43 | echo "Unknown option: $arg" 44 | echo "Use --help for usage information" 45 | exit 1 46 | ;; 47 | esac 48 | done 49 | 50 | # Check for required tools 51 | check_tool() { 52 | if ! command -v $1 &> /dev/null; then 53 | echo "${RED}Error: $1 is not installed or not in PATH${NC}" 54 | echo "To install: $2" 55 | return 1 56 | fi 57 | return 0 58 | } 59 | 60 | # Don't exit on error as we want to try all formatting stages 61 | set +e 62 | 63 | ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" 64 | 65 | # ANSI color codes 66 | GREEN='\033[0;32m' 67 | RED='\033[0;31m' 68 | YELLOW='\033[0;33m' 69 | NC='\033[0m' # No Color 70 | 71 | # Print banner 72 | echo "${YELLOW}=== SAGE Code Beautifier ===${NC}" 73 | 74 | # Format C code 75 | if $FORMAT_C; then 76 | echo -n "Formatting C code... " 77 | if check_tool clang-format "brew install clang-format"; then 78 | if cd "${ROOT_DIR}" && find . \( -name "*.c" -o -name "*.h" \) | xargs clang-format -i -style=LLVM > /dev/null 2>&1; then 79 | echo "${GREEN}✓${NC}" 80 | else 81 | echo "${RED}✗${NC}" 82 | echo "${RED}Error formatting C code. See details below:${NC}" 83 | cd "${ROOT_DIR}" && find . \( -name "*.c" -o -name "*.h" \) | xargs clang-format -i -style=LLVM 84 | fi 85 | else 86 | echo "${RED}✗ (tool not found)${NC}" 87 | fi 88 | fi 89 | 90 | # Format Python code 91 | if $FORMAT_PY; then 92 | # Format with Black 93 | echo -n "Formatting Python code with Black... " 94 | if check_tool black "pip install black"; then 95 | if black --quiet "${ROOT_DIR}" 2> /tmp/black_errors.log; then 96 | echo "${GREEN}✓${NC}" 97 | else 98 | echo "${RED}✗${NC}" 99 | echo "${RED}Black encountered errors:${NC}" 100 | cat /tmp/black_errors.log 101 | fi 102 | else 103 | echo "${RED}✗ (tool not found)${NC}" 104 | fi 105 | 106 | # Sort imports with isort 107 | echo -n "Sorting Python imports with isort... " 108 | if check_tool isort "pip install isort"; then 109 | if isort --profile black --quiet "${ROOT_DIR}" 2> /tmp/isort_errors.log; then 110 | echo "${GREEN}✓${NC}" 111 | else 112 | echo "${RED}✗${NC}" 113 | echo "${RED}isort encountered errors:${NC}" 114 | cat /tmp/isort_errors.log 115 | fi 116 | else 117 | echo "${RED}✗ (tool not found)${NC}" 118 | fi 119 | fi 120 | 121 | # Check if any errors occurred 122 | if $FORMAT_PY; then 123 | if command -v black &> /dev/null && command -v isort &> /dev/null; then 124 | if [ -s /tmp/black_errors.log ] || [ -s /tmp/isort_errors.log ]; then 125 | echo "${YELLOW}Some Python files could not be formatted. See errors above.${NC}" 126 | echo "Tip: For Python 2 files, consider converting to Python 3 with '2to3 -w filename.py'" 127 | echo " or manually adding parentheses to print statements." 128 | fi 129 | elif [ "$FORMAT_C" = true ] && [ "$FORMAT_PY" = true ]; then 130 | echo "${YELLOW}Note: Python formatting tools were not available.${NC}" 131 | echo "To install: pip install black isort" 132 | fi 133 | fi 134 | 135 | if $FORMAT_C && ! command -v clang-format &> /dev/null && [ "$FORMAT_PY" = true ]; then 136 | echo "${YELLOW}Note: C formatting tool (clang-format) was not available.${NC}" 137 | echo "To install: brew install clang-format" 138 | fi 139 | 140 | if { $FORMAT_C && command -v clang-format &> /dev/null; } || \ 141 | { $FORMAT_PY && command -v black &> /dev/null && command -v isort &> /dev/null && [ ! -s /tmp/black_errors.log ] && [ ! -s /tmp/isort_errors.log ]; }; then 142 | echo "${GREEN}Formatting completed successfully for all available tools!${NC}" 143 | fi 144 | 145 | # Clean up temporary files 146 | rm -f /tmp/black_errors.log /tmp/isort_errors.log 147 | 148 | echo "${YELLOW}=== Formatting Complete ===${NC}" 149 | -------------------------------------------------------------------------------- /output/sage-plot/figures/gas_fraction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Gas Fraction Plot 5 | 6 | This module generates a plot showing the gas fraction vs. stellar mass for SAGE galaxy data. 7 | """ 8 | 9 | import os 10 | import random 11 | 12 | import matplotlib.pyplot as plt 13 | import numpy as np 14 | from figures import ( 15 | AXIS_LABEL_SIZE, 16 | IN_FIGURE_TEXT_SIZE, 17 | LEGEND_FONT_SIZE, 18 | get_stellar_mass_label, 19 | setup_legend, 20 | setup_plot_fonts, 21 | ) 22 | from matplotlib.ticker import MultipleLocator 23 | 24 | 25 | def plot( 26 | galaxies, 27 | volume, 28 | metadata, 29 | params, 30 | output_dir="plots", 31 | output_format=".png", 32 | verbose=False, 33 | ): 34 | """ 35 | Create a gas fraction vs. stellar mass plot. 36 | 37 | Args: 38 | galaxies: Galaxy data as a numpy recarray 39 | volume: Simulation volume in (Mpc/h)^3 40 | metadata: Dictionary with additional metadata 41 | params: Dictionary with SAGE parameters 42 | output_dir: Output directory for the plot 43 | output_format: File format for the output 44 | 45 | Returns: 46 | Path to the saved plot file 47 | """ 48 | # Set random seed for reproducibility when sampling points 49 | random.seed(2222) 50 | 51 | # Set up the figure 52 | fig, ax = plt.subplots(figsize=(8, 6)) 53 | 54 | # Apply consistent font settings 55 | setup_plot_fonts(ax) 56 | 57 | # Extract necessary metadata 58 | hubble_h = metadata["hubble_h"] 59 | 60 | # Maximum number of points to plot (for better performance and readability) 61 | dilute = 7500 62 | 63 | # First filter for valid mass values - avoid division by zero 64 | valid_mass = ( 65 | (galaxies.Type == 0) 66 | & (galaxies.StellarMass > 0.0) 67 | & (galaxies.StellarMass + galaxies.ColdGas > 0.0) 68 | ) 69 | 70 | # Calculate ratio safely for valid galaxies 71 | bulge_ratio = np.zeros_like(galaxies.StellarMass) 72 | bulge_ratio[valid_mass] = ( 73 | galaxies.BulgeMass[valid_mass] / galaxies.StellarMass[valid_mass] 74 | ) 75 | 76 | # Now apply all filters 77 | w = np.where(valid_mass & (bulge_ratio > 0.1) & (bulge_ratio < 0.5))[0] 78 | 79 | # Check if we have any galaxies to plot 80 | if len(w) == 0: 81 | print("No suitable galaxies found for gas fraction plot") 82 | # Create an empty plot with a message 83 | ax.text( 84 | 0.5, 85 | 0.5, 86 | "No suitable galaxies found for gas fraction plot", 87 | horizontalalignment="center", 88 | verticalalignment="center", 89 | transform=ax.transAxes, 90 | fontsize=IN_FIGURE_TEXT_SIZE, 91 | ) 92 | 93 | # Save the figure 94 | os.makedirs(output_dir, exist_ok=True) 95 | output_path = os.path.join(output_dir, f"GasFraction{output_format}") 96 | plt.savefig(output_path) 97 | plt.close() 98 | return output_path 99 | 100 | # If we have too many galaxies, randomly sample a subset 101 | if len(w) > dilute: 102 | w = random.sample(list(w), dilute) 103 | 104 | # Calculate gas fraction and convert stellar mass to log scale 105 | stellar_mass = np.log10(galaxies.StellarMass[w] * 1.0e10 / hubble_h) 106 | gas_fraction = galaxies.ColdGas[w] / (galaxies.StellarMass[w] + galaxies.ColdGas[w]) 107 | 108 | # Print some debug information if verbose mode is enabled 109 | if verbose: 110 | print(f"Gas Fraction plot debug:") 111 | print(f" Number of galaxies plotted: {len(w)}") 112 | print( 113 | f" Stellar mass range: {min(stellar_mass):.2f} to {max(stellar_mass):.2f}" 114 | ) 115 | print( 116 | f" Gas fraction range: {min(gas_fraction):.3f} to {max(gas_fraction):.3f}" 117 | ) 118 | 119 | # Plot the galaxy data 120 | ax.scatter( 121 | stellar_mass, 122 | gas_fraction, 123 | marker="o", 124 | s=1, 125 | c="k", 126 | alpha=0.5, 127 | label="Model Sb/c galaxies", 128 | ) 129 | 130 | # Customize the plot 131 | ax.set_xlabel(get_stellar_mass_label(), fontsize=AXIS_LABEL_SIZE) 132 | ax.set_ylabel(r"Cold Mass / (Cold+Stellar Mass)", fontsize=AXIS_LABEL_SIZE) 133 | 134 | # Set the x and y axis minor ticks 135 | ax.xaxis.set_minor_locator(MultipleLocator(0.5)) 136 | ax.yaxis.set_minor_locator(MultipleLocator(0.05)) 137 | 138 | # Set axis limits - matching the original plot 139 | ax.set_xlim(8.0, 12.0) 140 | ax.set_ylim(0.0, 1.0) 141 | 142 | # Add consistently styled legend 143 | setup_legend(ax, loc="upper right") 144 | 145 | # Save the figure, ensuring the output directory exists 146 | try: 147 | os.makedirs(output_dir, exist_ok=True) 148 | except Exception as e: 149 | print(f"Warning: Could not create output directory {output_dir}: {e}") 150 | # Try to use a subdirectory of the current directory as fallback 151 | output_dir = "./plots" 152 | os.makedirs(output_dir, exist_ok=True) 153 | 154 | output_path = os.path.join(output_dir, f"GasFraction{output_format}") 155 | if verbose: 156 | print(f"Saving Gas Fraction plot to: {output_path}") 157 | plt.savefig(output_path) 158 | plt.close() 159 | 160 | return output_path 161 | -------------------------------------------------------------------------------- /output/sage-plot/figures/mass_reservoir_scatter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Mass Reservoir Scatter Plot 5 | 6 | This module generates a scatter plot showing the mass in different galaxy components vs. halo mass. 7 | """ 8 | 9 | import os 10 | import random 11 | 12 | import matplotlib.pyplot as plt 13 | import numpy as np 14 | from figures import ( 15 | AXIS_LABEL_SIZE, 16 | IN_FIGURE_TEXT_SIZE, 17 | LEGEND_FONT_SIZE, 18 | setup_legend, 19 | setup_plot_fonts, 20 | ) 21 | from matplotlib.ticker import MultipleLocator 22 | 23 | 24 | def plot( 25 | galaxies, 26 | volume, 27 | metadata, 28 | params, 29 | output_dir="plots", 30 | output_format=".png", 31 | verbose=False, 32 | ): 33 | """ 34 | Create a mass reservoir scatter plot. 35 | 36 | Args: 37 | galaxies: Galaxy data as a numpy recarray 38 | volume: Simulation volume in (Mpc/h)^3 39 | metadata: Dictionary with additional metadata 40 | params: Dictionary with SAGE parameters 41 | output_dir: Output directory for the plot 42 | output_format: File format for the output 43 | 44 | Returns: 45 | Path to the saved plot file 46 | """ 47 | # Set random seed for reproducibility when sampling points 48 | random.seed(2222) 49 | 50 | # Set up the figure 51 | fig, ax = plt.subplots(figsize=(8, 6)) 52 | 53 | # Apply consistent font settings 54 | setup_plot_fonts(ax) 55 | 56 | # Extract necessary metadata 57 | hubble_h = metadata["hubble_h"] 58 | 59 | # Maximum number of points to plot (for better performance and readability) 60 | dilute = 7500 61 | 62 | # Filter for type 0 (central) galaxies with non-zero Mvir 63 | w = np.where( 64 | (galaxies.Type == 0) & (galaxies.Mvir > 1.0) & (galaxies.StellarMass > 0.0) 65 | )[0] 66 | 67 | # Check if we have any galaxies to plot 68 | if len(w) == 0: 69 | print("No central galaxies found with Mvir > 1.0 and StellarMass > 0.0") 70 | # Create an empty plot with a message 71 | ax.text( 72 | 0.5, 73 | 0.5, 74 | "No central galaxies found with Mvir > 1.0 and StellarMass > 0.0", 75 | horizontalalignment="center", 76 | verticalalignment="center", 77 | transform=ax.transAxes, 78 | fontsize=IN_FIGURE_TEXT_SIZE, 79 | ) 80 | 81 | # Save the figure 82 | os.makedirs(output_dir, exist_ok=True) 83 | output_path = os.path.join(output_dir, f"MassReservoirScatter{output_format}") 84 | plt.savefig(output_path) 85 | plt.close() 86 | return output_path 87 | 88 | # If we have too many galaxies, randomly sample a subset 89 | if len(w) > dilute: 90 | w = random.sample(list(w), dilute) 91 | 92 | # Get halo mass in log10 Msun units 93 | mvir = np.log10(galaxies.Mvir[w] * 1.0e10) 94 | 95 | # Get component masses in log10 Msun units 96 | stellar_mass = np.log10(galaxies.StellarMass[w] * 1.0e10) 97 | cold_gas = np.log10(np.maximum(galaxies.ColdGas[w] * 1.0e10, 1.0)) # Avoid log(0) 98 | hot_gas = np.log10(np.maximum(galaxies.HotGas[w] * 1.0e10, 1.0)) 99 | ejected_gas = np.log10(np.maximum(galaxies.EjectedMass[w] * 1.0e10, 1.0)) 100 | ics = np.log10(np.maximum(galaxies.IntraClusterStars[w] * 1.0e10, 1.0)) 101 | 102 | # Print some debug information 103 | # Print some debug information if verbose mode is enabled 104 | if verbose: 105 | print(f" Number of galaxies plotted: {len(w)}") 106 | print(f" Halo mass range: {min(mvir):.2f} to {max(mvir):.2f}") 107 | print( 108 | f" Stellar mass range: {min(stellar_mass):.2f} to {max(stellar_mass):.2f}" 109 | ) 110 | 111 | # Plot each mass component 112 | ax.scatter(mvir, stellar_mass, marker="o", s=0.8, c="k", alpha=0.5, label="Stars") 113 | ax.scatter(mvir, cold_gas, marker="o", s=0.8, c="blue", alpha=0.5, label="Cold gas") 114 | ax.scatter(mvir, hot_gas, marker="o", s=0.8, c="red", alpha=0.5, label="Hot gas") 115 | ax.scatter( 116 | mvir, ejected_gas, marker="o", s=0.8, c="green", alpha=0.5, label="Ejected gas" 117 | ) 118 | ax.scatter( 119 | mvir, ics, marker="x", s=5, c="yellow", alpha=0.7, label="Intracluster stars" 120 | ) 121 | 122 | # Customize the plot 123 | ax.set_xlabel(r"log M$_{\rm vir}$ (h$^{-1}$ M$_{\odot}$)", fontsize=AXIS_LABEL_SIZE) 124 | ax.set_ylabel(r"Stellar, cold, hot, ejected, ICS mass", fontsize=AXIS_LABEL_SIZE) 125 | 126 | # Set the x and y axis minor ticks 127 | ax.xaxis.set_minor_locator(MultipleLocator(0.5)) 128 | ax.yaxis.set_minor_locator(MultipleLocator(0.5)) 129 | 130 | # Set axis limits - matching the original plot 131 | x_min = max(10.0, min(mvir) - 0.5) 132 | x_max = min(14.0, max(mvir) + 0.5) 133 | y_min = max(7.5, min(min(stellar_mass), min(cold_gas), min(hot_gas)) - 0.5) 134 | y_max = min(12.5, max(max(stellar_mass), max(cold_gas), max(hot_gas)) + 0.5) 135 | 136 | ax.set_xlim(x_min, x_max) 137 | ax.set_ylim(y_min, y_max) 138 | 139 | # Add text annotation 'All' in the bottom-right corner 140 | ax.text( 141 | 0.95, 0.05, r"All", transform=ax.transAxes, fontsize=12, ha="right", va="bottom" 142 | ) 143 | 144 | # Add consistently styled legend 145 | setup_legend(ax, loc="upper left") 146 | 147 | # Save the figure, ensuring the output directory exists 148 | try: 149 | os.makedirs(output_dir, exist_ok=True) 150 | except Exception as e: 151 | print(f"Warning: Could not create output directory {output_dir}: {e}") 152 | # Try to use a subdirectory of the current directory as fallback 153 | output_dir = "./plots" 154 | os.makedirs(output_dir, exist_ok=True) 155 | 156 | output_path = os.path.join(output_dir, f"MassReservoirScatter{output_format}") 157 | if verbose: 158 | print(f"Saving Mass Reservoir Scatter plot to: {output_path}") 159 | plt.savefig(output_path) 160 | plt.close() 161 | 162 | return output_path 163 | -------------------------------------------------------------------------------- /output/sage-plot/figures/bulge_mass_fraction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Bulge Mass Fraction Plot 5 | 6 | This module generates a plot showing the bulge and disk mass fractions vs. stellar mass for SAGE galaxy data. 7 | """ 8 | 9 | import os 10 | 11 | import matplotlib.pyplot as plt 12 | import numpy as np 13 | from figures import ( 14 | AXIS_LABEL_SIZE, 15 | IN_FIGURE_TEXT_SIZE, 16 | LEGEND_FONT_SIZE, 17 | get_stellar_mass_label, 18 | setup_legend, 19 | setup_plot_fonts, 20 | ) 21 | from matplotlib.ticker import MultipleLocator 22 | 23 | 24 | def plot( 25 | galaxies, 26 | volume, 27 | metadata, 28 | params, 29 | output_dir="plots", 30 | output_format=".png", 31 | verbose=False, 32 | ): 33 | """ 34 | Create a bulge mass fraction vs. stellar mass plot. 35 | 36 | Args: 37 | galaxies: Galaxy data as a numpy recarray 38 | volume: Simulation volume in (Mpc/h)^3 39 | metadata: Dictionary with additional metadata 40 | params: Dictionary with SAGE parameters 41 | output_dir: Output directory for the plot 42 | output_format: File format for the output 43 | 44 | Returns: 45 | Path to the saved plot file 46 | """ 47 | # Set up the figure 48 | fig, ax = plt.subplots(figsize=(8, 6)) 49 | 50 | # Apply consistent font settings 51 | setup_plot_fonts(ax) 52 | 53 | # Extract necessary metadata 54 | hubble_h = metadata["hubble_h"] 55 | 56 | # Calculate bulge and disk fractions 57 | # Handle division by zero safely 58 | valid_galaxies = np.where(galaxies.StellarMass > 0.0)[0] 59 | 60 | # Check if we have any galaxies to plot 61 | if len(valid_galaxies) == 0: 62 | print("No galaxies found with stellar mass > 0") 63 | # Create an empty plot with a message 64 | ax.text( 65 | 0.5, 66 | 0.5, 67 | "No galaxies found with stellar mass > 0", 68 | horizontalalignment="center", 69 | verticalalignment="center", 70 | transform=ax.transAxes, 71 | fontsize=IN_FIGURE_TEXT_SIZE, 72 | ) 73 | 74 | # Save the figure 75 | os.makedirs(output_dir, exist_ok=True) 76 | output_path = os.path.join(output_dir, f"BulgeMassFraction{output_format}") 77 | plt.savefig(output_path) 78 | plt.close() 79 | return output_path 80 | 81 | # Calculate bulge and disk fractions 82 | f_bulge = galaxies.BulgeMass[valid_galaxies] / galaxies.StellarMass[valid_galaxies] 83 | f_disk = 1.0 - f_bulge 84 | 85 | # Convert stellar mass to log scale 86 | mass = np.log10(galaxies.StellarMass[valid_galaxies] * 1.0e10 / hubble_h) 87 | 88 | # Set up mass bins for the averaging 89 | binwidth = 0.2 90 | shift = binwidth / 2.0 91 | mass_range = np.arange(8.5 - shift, 12.0 + shift, binwidth) 92 | bins = len(mass_range) 93 | 94 | # Initialize arrays for average values and variances 95 | f_bulge_ave = np.zeros(bins) 96 | f_bulge_var = np.zeros(bins) 97 | f_disk_ave = np.zeros(bins) 98 | f_disk_var = np.zeros(bins) 99 | 100 | # Calculate average values and variances in each bin 101 | for i in range(bins - 1): 102 | bin_mask = (mass >= mass_range[i]) & (mass < mass_range[i + 1]) 103 | if np.sum(bin_mask) > 0: 104 | f_bulge_ave[i] = np.mean(f_bulge[bin_mask]) 105 | f_bulge_var[i] = np.std(f_bulge[bin_mask]) ** 2 # Variance 106 | f_disk_ave[i] = np.mean(f_disk[bin_mask]) 107 | f_disk_var[i] = np.std(f_disk[bin_mask]) ** 2 # Variance 108 | 109 | # Print some debug information if verbose mode is enabled 110 | if verbose: 111 | print(f"Bulge Mass Fraction plot debug:") 112 | print(f" Number of galaxies: {len(valid_galaxies)}") 113 | print(f" Stellar mass range: {min(mass):.2f} to {max(mass):.2f}") 114 | print(f" Bulge fraction range: {min(f_bulge):.3f} to {max(f_bulge):.3f}") 115 | print(f" Number of mass bins: {bins}") 116 | 117 | # Plot bulge fractions 118 | mask_bulge = f_bulge_ave > 0.0 119 | ax.plot( 120 | mass_range[mask_bulge] + shift, f_bulge_ave[mask_bulge], "r-", label="bulge" 121 | ) 122 | ax.fill_between( 123 | mass_range[mask_bulge] + shift, 124 | np.clip(f_bulge_ave[mask_bulge] + np.sqrt(f_bulge_var[mask_bulge]), 0, 1), 125 | np.clip(f_bulge_ave[mask_bulge] - np.sqrt(f_bulge_var[mask_bulge]), 0, 1), 126 | facecolor="red", 127 | alpha=0.25, 128 | ) 129 | 130 | # Plot disk fractions 131 | mask_disk = f_disk_ave > 0.0 132 | ax.plot( 133 | mass_range[mask_disk] + shift, f_disk_ave[mask_disk], "k-", label="disk stars" 134 | ) 135 | ax.fill_between( 136 | mass_range[mask_disk] + shift, 137 | np.clip(f_disk_ave[mask_disk] + np.sqrt(f_disk_var[mask_disk]), 0, 1), 138 | np.clip(f_disk_ave[mask_disk] - np.sqrt(f_disk_var[mask_disk]), 0, 1), 139 | facecolor="black", 140 | alpha=0.25, 141 | ) 142 | 143 | # Customize the plot 144 | ax.set_xlabel(get_stellar_mass_label(), fontsize=AXIS_LABEL_SIZE) 145 | ax.set_ylabel(r"Stellar Mass Fraction", fontsize=AXIS_LABEL_SIZE) 146 | 147 | # Set axis limits - matching the original plot 148 | ax.set_xlim(mass_range[0], mass_range[bins - 1]) 149 | ax.set_ylim(0.0, 1.05) 150 | 151 | # Add consistently styled legend 152 | setup_legend(ax, loc="upper right") 153 | 154 | # Save the figure, ensuring the output directory exists 155 | try: 156 | os.makedirs(output_dir, exist_ok=True) 157 | except Exception as e: 158 | print(f"Warning: Could not create output directory {output_dir}: {e}") 159 | # Try to use a subdirectory of the current directory as fallback 160 | output_dir = "./plots" 161 | os.makedirs(output_dir, exist_ok=True) 162 | 163 | output_path = os.path.join(output_dir, f"BulgeMassFraction{output_format}") 164 | if verbose: 165 | print(f"Saving Bulge Mass Fraction plot to: {output_path}") 166 | plt.savefig(output_path) 167 | plt.close() 168 | 169 | return output_path 170 | -------------------------------------------------------------------------------- /code/error_handling_guidelines.md: -------------------------------------------------------------------------------- 1 | # SAGE Error Handling Guidelines 2 | 3 | This document outlines guidelines for consistent error handling across the SAGE codebase. It defines when to use each error level and provides examples to ensure a uniform approach to error reporting and handling. 4 | 5 | ## Error Severity Levels 6 | 7 | SAGE uses five severity levels for error handling, each with a specific purpose: 8 | 9 | 1. **FATAL_ERROR**: For unrecoverable errors requiring immediate termination 10 | 2. **ERROR_LOG**: For recoverable errors where processing can continue 11 | 3. **WARNING_LOG**: For potential issues that don't affect correctness 12 | 4. **INFO_LOG**: For important operational information 13 | 5. **DEBUG_LOG**: For detailed debugging information 14 | 15 | ## When to Use Each Error Level 16 | 17 | ### FATAL_ERROR 18 | 19 | Use for unrecoverable errors that prevent further operation and require immediate program termination. 20 | 21 | **Use when**: 22 | - File open/read failures that prevent further processing 23 | - Memory allocation failures for critical components 24 | - Invalid parameter values that violate core assumptions 25 | - Unsupported input types or formats 26 | - Unexpected conditions that make it impossible to continue safely 27 | 28 | **Examples**: 29 | ```c 30 | if (!(file = fopen(filename, "r"))) { 31 | FATAL_ERROR("Failed to open required input file '%s'. Error: %s", filename, strerror(errno)); 32 | } 33 | 34 | if (buffer == NULL) { 35 | FATAL_ERROR("Memory allocation failed for buffer (%zu bytes)", size); 36 | } 37 | 38 | if (my_TreeType < 0 || my_TreeType >= NUM_TREE_TYPES) { 39 | FATAL_ERROR("Unsupported tree type %d. Valid range: 0-%d", my_TreeType, NUM_TREE_TYPES-1); 40 | } 41 | ``` 42 | 43 | ### ERROR_LOG 44 | 45 | Use for recoverable errors where processing can continue but with potential limitations or fallbacks. 46 | 47 | **Use when**: 48 | - Non-critical file write failures 49 | - When operations succeed but with sub-optimal results 50 | - When a fallback approach can be used 51 | - When skipping a processing step is acceptable 52 | 53 | **Examples**: 54 | ```c 55 | if (nwritten != expected_count) { 56 | ERROR_LOG("Failed to write complete data to file '%s'. Expected %d elements, wrote %d elements", 57 | filename, expected_count, nwritten); 58 | // Continue with limited functionality 59 | } 60 | 61 | if (cooling_table == NULL) { 62 | ERROR_LOG("No cooling table available for metallicity %g. Using nearest available table", 63 | metallicity); 64 | // Use nearest available table 65 | } 66 | ``` 67 | 68 | ### WARNING_LOG 69 | 70 | Use for potential issues that don't affect correctness but might indicate problems or unexpected behavior. 71 | 72 | **Use when**: 73 | - Sub-optimal parameters are detected 74 | - Performance concerns arise 75 | - Unusual but valid input values are encountered 76 | - Using a default value because a specified value is out of range 77 | 78 | **Examples**: 79 | ```c 80 | if (Gal[p].BulgeMass / Gal[p].StellarMass > 0.99) { 81 | WARNING_LOG("Bulge mass nearly equals total stellar mass in galaxy %d (%.2f%%)", 82 | p, 100.0 * Gal[p].BulgeMass / Gal[p].StellarMass); 83 | } 84 | 85 | if (Gal[p].MetalsColdGas > Gal[p].ColdGas) { 86 | WARNING_LOG("Metal mass exceeds gas mass in galaxy %d. Metallicity: %.2f", 87 | p, Gal[p].MetalsColdGas / Gal[p].ColdGas); 88 | } 89 | 90 | if (cooling_time < minimum_timestep) { 91 | WARNING_LOG("Cooling time (%.2e) shorter than minimum timestep (%.2e)", 92 | cooling_time, minimum_timestep); 93 | } 94 | ``` 95 | 96 | ### INFO_LOG 97 | 98 | Use for important operational information that doesn't indicate errors or warnings. 99 | 100 | **Use when**: 101 | - Reporting processing milestones 102 | - Logging resource usage information 103 | - Reporting configuration settings 104 | - Providing update on progress 105 | 106 | **Examples**: 107 | ```c 108 | INFO_LOG("Processing tree %d of %d (%d%% complete)", 109 | treenr+1, Ntrees, (treenr+1)*100/Ntrees); 110 | 111 | INFO_LOG("Memory usage: %d MB", (int)(get_memory_usage() / (1024*1024))); 112 | 113 | INFO_LOG("Output galaxies written to: %s", output_filename); 114 | ``` 115 | 116 | ### DEBUG_LOG 117 | 118 | Use for detailed debugging information that is valuable during development but not necessary for regular operation. 119 | 120 | **Use when**: 121 | - Tracking function entry/exit points 122 | - Logging intermediate calculation values 123 | - Reporting progress within loops 124 | - Providing detailed state information 125 | 126 | **Examples**: 127 | ```c 128 | DEBUG_LOG("Entering function with params: x=%g, y=%g", x, y); 129 | 130 | DEBUG_LOG("Intermediate calculation result: %g", intermediate_value); 131 | 132 | DEBUG_LOG("Galaxy %d properties: StellarMass=%g, ColdGas=%g", 133 | p, Gal[p].StellarMass, Gal[p].ColdGas); 134 | ``` 135 | 136 | ## Error Handling Best Practices 137 | 138 | 1. **Be Specific**: Include enough context in error messages to identify the problem and its location. Include variable values, file names, and other relevant information. 139 | 140 | 2. **Be Consistent**: Use the appropriate error level as defined in this document. 141 | 142 | 3. **Be Helpful**: Where possible, suggest remedies or alternatives in error messages. 143 | 144 | 4. **Check Return Values**: Always check return values from system calls and library functions. 145 | 146 | 5. **Memory Management**: Always verify memory allocations and handle failures gracefully. 147 | 148 | 6. **File Operations**: Check for failures in file operations and provide context in error messages. 149 | 150 | 7. **Error Propagation**: Consider how errors propagate up the call stack. Lower-level functions should report errors to higher-level functions when appropriate. 151 | 152 | ## Legacy ABORT Macro 153 | 154 | The SAGE codebase contains a legacy `ABORT` macro that redirects to `FATAL_ERROR` for backward compatibility: 155 | 156 | ```c 157 | #define ABORT(sigterm) FATAL_ERROR("Program aborted with exit code %d", sigterm) 158 | ``` 159 | 160 | For consistency, prefer using `FATAL_ERROR` directly with a descriptive error message rather than `ABORT` for new code. 161 | -------------------------------------------------------------------------------- /code/io_tree_binary.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file io/tree_binary.c 3 | * @brief Functions for reading binary merger tree files 4 | * 5 | * This file implements functionality for loading merger trees from 6 | * binary format files. It handles the reading of tree metadata and 7 | * halo data for individual trees, providing an interface to the core 8 | * SAGE code that is independent of the specific file format. 9 | * 10 | * Binary format trees are the traditional SAGE input format, consisting 11 | * of a simple structure with tree counts, halo counts, and arrays of 12 | * halo data. This format is efficient to read but less flexible than 13 | * newer formats like HDF5. 14 | * 15 | * Key functions: 16 | * - load_tree_table_binary(): Reads tree metadata from a binary file 17 | * - load_tree_binary(): Loads a specific tree's halo data 18 | * - close_binary_file(): Closes the binary file 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "config.h" 32 | #include "core_proto.h" 33 | #include "globals.h" 34 | #include "io_tree.h" 35 | #include "io_tree_binary.h" 36 | #include "io_util.h" 37 | #include "types.h" 38 | #include "util_error.h" 39 | 40 | // Local Variables // 41 | 42 | static FILE *load_fd; 43 | 44 | // Local Proto-Types // 45 | 46 | // External Functions // 47 | 48 | #ifndef MAX_BUF_SIZE 49 | #define MAX_BUF_SIZE (3 * MAX_STRING_LEN + 40) 50 | #endif 51 | 52 | /** 53 | * @brief Loads merger tree metadata from a binary file 54 | * 55 | * @param filenr File number to load 56 | * 57 | * This function opens and reads the metadata from a binary merger tree file. 58 | * It extracts: 59 | * 1. The number of trees in the file 60 | * 2. The total number of halos across all trees 61 | * 3. The number of halos in each individual tree 62 | * 63 | * It allocates memory for tree metadata arrays and calculates the 64 | * starting index of each tree in the file. This information is used 65 | * later when loading individual trees. 66 | * 67 | * The function also updates the SimState structure to maintain consistency 68 | * with the global variables. 69 | */ 70 | void load_tree_table_binary(int32_t filenr) { 71 | int i, totNHalos; 72 | char buf[MAX_BUF_SIZE + 1]; 73 | 74 | // Open the file 75 | snprintf(buf, MAX_BUF_SIZE, "%s/%s.%d%s", SageConfig.SimulationDir, 76 | SageConfig.TreeName, filenr, SageConfig.TreeExtension); 77 | if (!(load_fd = fopen(buf, "r"))) { 78 | FATAL_ERROR("Failed to open binary tree file '%s' (filenr %d)", buf, 79 | filenr); 80 | } 81 | 82 | // For simplicity, assume host endianness for legacy files 83 | set_file_endianness(SAGE_HOST_ENDIAN); 84 | DEBUG_LOG("Using legacy headerless file format (assuming %s endian)", 85 | (SAGE_HOST_ENDIAN == SAGE_LITTLE_ENDIAN) ? "little" : "big"); 86 | 87 | // Read the tree metadata 88 | if (fread(&Ntrees, sizeof(int), 1, load_fd) != 1) { 89 | FATAL_ERROR("Failed to read Ntrees from file '%s'", buf); 90 | } 91 | SimState.Ntrees = Ntrees; /* Update SimState directly */ 92 | 93 | if (fread(&totNHalos, sizeof(int), 1, load_fd) != 1) { 94 | FATAL_ERROR("Failed to read totNHalos from file '%s'", buf); 95 | } 96 | 97 | DEBUG_LOG("Reading %d trees with %d total halos", Ntrees, totNHalos); 98 | 99 | // Allocate arrays for tree data 100 | TreeNHalos = mymalloc(sizeof(int) * Ntrees); 101 | if (TreeNHalos == NULL) { 102 | FATAL_ERROR("Failed to allocate memory for TreeNHalos array"); 103 | } 104 | SimState.TreeNHalos = TreeNHalos; /* Update SimState pointer directly */ 105 | 106 | TreeFirstHalo = mymalloc(sizeof(int) * Ntrees); 107 | if (TreeFirstHalo == NULL) { 108 | FATAL_ERROR("Failed to allocate memory for TreeFirstHalo array"); 109 | } 110 | SimState.TreeFirstHalo = TreeFirstHalo; /* Update SimState pointer directly */ 111 | 112 | // Read the number of halos per tree - using direct fread for now 113 | if (fread(TreeNHalos, sizeof(int), Ntrees, load_fd) != Ntrees) { 114 | FATAL_ERROR("Failed to read tree halo counts from file '%s'", buf); 115 | } 116 | 117 | // Calculate starting indices for each tree 118 | if (Ntrees > 0) { 119 | TreeFirstHalo[0] = 0; 120 | for (i = 1; i < Ntrees; i++) 121 | TreeFirstHalo[i] = TreeFirstHalo[i - 1] + TreeNHalos[i - 1]; 122 | } 123 | } 124 | 125 | /** 126 | * @brief Loads a specific merger tree from a binary file 127 | * 128 | * @param filenr File number containing the tree 129 | * @param treenr Index of the tree to load 130 | * 131 | * This function reads the halo data for a specific merger tree from 132 | * an already-opened binary file. It: 133 | * 1. Allocates memory for the halos in this tree 134 | * 2. Reads the halo data from the file into the allocated memory 135 | * 136 | * The function assumes that load_tree_table_binary() has already been 137 | * called to load the tree metadata and that the file is properly positioned 138 | * for reading. 139 | * 140 | * The halos are stored in the global Halo array for processing by the 141 | * SAGE model. 142 | */ 143 | void load_tree_binary(int32_t filenr, int32_t treenr) { 144 | // must have an FD 145 | assert(load_fd); 146 | 147 | Halo = mymalloc(sizeof(struct halo_data) * TreeNHalos[treenr]); 148 | if (Halo == NULL) { 149 | FATAL_ERROR("Failed to allocate memory for Halo array with %d halos", 150 | TreeNHalos[treenr]); 151 | } 152 | 153 | // Use direct fread to avoid our problematic wrapper 154 | if (fread(Halo, sizeof(struct halo_data), TreeNHalos[treenr], load_fd) != 155 | TreeNHalos[treenr]) { 156 | FATAL_ERROR("Failed to read halo data for tree %d", treenr); 157 | } 158 | } 159 | 160 | /** 161 | * @brief Closes the binary merger tree file 162 | * 163 | * This function closes the file handle for the currently open binary 164 | * merger tree file. It's called when all trees have been processed 165 | * or when switching to a different file. 166 | * 167 | * The function checks if the file is actually open before attempting 168 | * to close it, and sets the file handle to NULL after closing to 169 | * prevent multiple close attempts. 170 | */ 171 | void close_binary_file(void) { 172 | if (load_fd) { 173 | fclose(load_fd); 174 | load_fd = NULL; 175 | } 176 | } 177 | // Local Functions // 178 | -------------------------------------------------------------------------------- /code/core_simulation_state.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file core_simulation_state.c 3 | * @brief Functions for managing the simulation state structure 4 | * 5 | * This file implements functionality for managing the SAGE simulation state. 6 | * It provides functions to synchronize between the SimState structure and 7 | * global variables, maintaining backward compatibility with existing code 8 | * while supporting a more encapsulated approach using the SimState structure. 9 | * 10 | * The SimState structure centralizes all simulation state variables that 11 | * were previously maintained as global variables, making it easier to 12 | * save and restore simulation state, track changes, and reduce global 13 | * variable dependencies. 14 | * 15 | * Key functions: 16 | * - sync_sim_state_to_globals(): Copies SimState values to global variables 17 | * - sync_globals_to_sim_state(): Copies global variable values to SimState 18 | * - initialize_sim_state(): Sets up initial SimState values 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "config.h" 26 | #include "constants.h" 27 | #include "core_proto.h" 28 | #include "globals.h" 29 | #include "types.h" 30 | #include "util_error.h" 31 | 32 | /** 33 | * @brief Updates global variables from the SimState structure 34 | * 35 | * This function copies all values from the SimState structure to their 36 | * corresponding global variables. It's used to maintain backward compatibility 37 | * with existing code that relies on global variables, while allowing the 38 | * simulation state to be encapsulated in the SimState structure. 39 | * 40 | * The function handles various types of data: 41 | * 1. Simple scalar values (counters, IDs) 42 | * 2. Arrays (via memcpy) 43 | * 3. Pointers (with special care to maintain pointer relationships) 44 | * 45 | * This synchronization is necessary when the SimState structure has been 46 | * modified and those changes need to be reflected in the global variables 47 | * used throughout the rest of the code. 48 | */ 49 | void sync_sim_state_to_globals(void) { 50 | /* Tree and galaxy counts */ 51 | Ntrees = SimState.Ntrees; 52 | NumGals = SimState.NumGals; 53 | MaxGals = SimState.MaxGals; 54 | FoF_MaxGals = SimState.FoF_MaxGals; 55 | GalaxyCounter = SimState.GalaxyCounter; 56 | TotHalos = SimState.TotHalos; 57 | 58 | /* Copy array values */ 59 | memcpy(TotGalaxies, SimState.TotGalaxies, sizeof(int) * ABSOLUTEMAXSNAPS); 60 | 61 | /* File and tree identifiers */ 62 | FileNum = SimState.FileNum; 63 | TreeID = SimState.TreeID; 64 | 65 | /* Snapshot information - handled differently as these can also be in 66 | * SageConfig */ 67 | MAXSNAPS = SimState.MAXSNAPS; 68 | Snaplistlen = SimState.Snaplistlen; 69 | NOUT = SimState.NOUT; 70 | memcpy(ListOutputSnaps, SimState.ListOutputSnaps, 71 | sizeof(int) * ABSOLUTEMAXSNAPS); 72 | 73 | /* Pointers - these need special care */ 74 | for (int i = 0; i < ABSOLUTEMAXSNAPS; i++) { 75 | if (i < NOUT) { 76 | TreeNgals[i] = SimState.TreeNgals[i]; 77 | } 78 | } 79 | FirstHaloInSnap = SimState.FirstHaloInSnap; 80 | TreeNHalos = SimState.TreeNHalos; 81 | TreeFirstHalo = SimState.TreeFirstHalo; 82 | } 83 | 84 | /** 85 | * @brief Updates the SimState structure from global variables 86 | * 87 | * This function copies all values from global variables to their 88 | * corresponding fields in the SimState structure. It's typically used 89 | * to initialize the SimState structure with the current global state 90 | * or to ensure the structure is up to date after global variables 91 | * have been modified. 92 | * 93 | * The function handles various types of data: 94 | * 1. Simple scalar values (counters, IDs) 95 | * 2. Arrays (via memcpy) 96 | * 3. Pointers (with special care to maintain pointer relationships) 97 | * 98 | * This synchronization is the inverse of sync_sim_state_to_globals() 99 | * and allows the simulation state to be captured and stored in a 100 | * single, self-contained structure. 101 | */ 102 | void sync_globals_to_sim_state(void) { 103 | /* Tree and galaxy counts */ 104 | SimState.Ntrees = Ntrees; 105 | SimState.NumGals = NumGals; 106 | SimState.MaxGals = MaxGals; 107 | SimState.FoF_MaxGals = FoF_MaxGals; 108 | SimState.GalaxyCounter = GalaxyCounter; 109 | SimState.TotHalos = TotHalos; 110 | 111 | /* Copy array values */ 112 | memcpy(SimState.TotGalaxies, TotGalaxies, sizeof(int) * ABSOLUTEMAXSNAPS); 113 | 114 | /* File and tree identifiers */ 115 | SimState.FileNum = FileNum; 116 | SimState.TreeID = TreeID; 117 | 118 | /* Snapshot information */ 119 | SimState.MAXSNAPS = MAXSNAPS; 120 | SimState.Snaplistlen = Snaplistlen; 121 | SimState.NOUT = NOUT; 122 | memcpy(SimState.ListOutputSnaps, ListOutputSnaps, 123 | sizeof(int) * ABSOLUTEMAXSNAPS); 124 | 125 | /* Pointers - these need special care */ 126 | for (int i = 0; i < ABSOLUTEMAXSNAPS; i++) { 127 | if (i < NOUT) { 128 | SimState.TreeNgals[i] = TreeNgals[i]; 129 | } else { 130 | SimState.TreeNgals[i] = NULL; 131 | } 132 | } 133 | SimState.FirstHaloInSnap = FirstHaloInSnap; 134 | SimState.TreeNHalos = TreeNHalos; 135 | SimState.TreeFirstHalo = TreeFirstHalo; 136 | } 137 | 138 | /** 139 | * @brief Initializes the SimState structure with default values 140 | * 141 | * This function sets up the initial values in the SimState structure 142 | * by first synchronizing from global variables and then updating 143 | * specific fields from the SageConfig structure. It ensures that the 144 | * simulation state is properly initialized at the start of a simulation 145 | * run with consistent values across all related data structures. 146 | * 147 | * The function: 148 | * 1. Copies current global variable values to SimState 149 | * 2. Updates snapshot-related fields from SageConfig 150 | * 3. Synchronizes back to globals to ensure consistency 151 | * 152 | * After this function completes, both the SimState structure and 153 | * global variables will contain the same, consistent set of values 154 | * for the simulation state. 155 | */ 156 | void initialize_sim_state(void) { 157 | /* Initialize the structure from global variables */ 158 | sync_globals_to_sim_state(); 159 | 160 | /* Update MAXSNAPS, Snaplistlen, NOUT, and ListOutputSnaps from SageConfig */ 161 | SimState.MAXSNAPS = SageConfig.MAXSNAPS; 162 | SimState.Snaplistlen = SageConfig.Snaplistlen; 163 | SimState.NOUT = SageConfig.NOUT; 164 | memcpy(SimState.ListOutputSnaps, SageConfig.ListOutputSnaps, 165 | sizeof(int) * ABSOLUTEMAXSNAPS); 166 | 167 | /* Synchronize back to globals for consistency */ 168 | sync_sim_state_to_globals(); 169 | } 170 | -------------------------------------------------------------------------------- /output/sage-plot/figures/velocity_distribution.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Velocity Distribution Plot 5 | 6 | This module generates a plot showing the distribution of galaxy velocities. 7 | """ 8 | 9 | import os 10 | 11 | import matplotlib.pyplot as plt 12 | import numpy as np 13 | from figures import ( 14 | AXIS_LABEL_SIZE, 15 | IN_FIGURE_TEXT_SIZE, 16 | LEGEND_FONT_SIZE, 17 | setup_legend, 18 | setup_plot_fonts, 19 | ) 20 | from matplotlib.ticker import MultipleLocator 21 | 22 | 23 | def plot( 24 | galaxies, 25 | volume, 26 | metadata, 27 | params, 28 | output_dir="plots", 29 | output_format=".png", 30 | verbose=False, 31 | ): 32 | """ 33 | Create a velocity distribution plot. 34 | 35 | Args: 36 | galaxies: Galaxy data as a numpy recarray 37 | volume: Simulation volume in (Mpc/h)^3 38 | metadata: Dictionary with additional metadata 39 | params: Dictionary with SAGE parameters 40 | output_dir: Output directory for the plot 41 | output_format: File format for the output 42 | 43 | Returns: 44 | Path to the saved plot file 45 | """ 46 | # Set up the figure 47 | fig, ax = plt.subplots(figsize=(8, 6)) 48 | 49 | # Apply consistent font settings 50 | setup_plot_fonts(ax) 51 | 52 | # Extract necessary metadata 53 | hubble_h = metadata["hubble_h"] 54 | 55 | # Set up histogram binning 56 | bin_min = -40.0 57 | bin_max = 40.0 58 | bin_width = 0.5 59 | nbins = int((bin_max - bin_min) / bin_width) 60 | 61 | # Get position and velocity data 62 | pos_x = galaxies.Pos[:, 0] / hubble_h # Convert to Mpc 63 | pos_y = galaxies.Pos[:, 1] / hubble_h 64 | pos_z = galaxies.Pos[:, 2] / hubble_h 65 | 66 | vel_x = galaxies.Vel[:, 0] # km/s 67 | vel_y = galaxies.Vel[:, 1] 68 | vel_z = galaxies.Vel[:, 2] 69 | 70 | # Calculate line-of-sight distance and velocity 71 | # For line-of-sight, we use the position vector from the origin 72 | dist_los = np.sqrt(pos_x**2 + pos_y**2 + pos_z**2) 73 | 74 | # Skip galaxies with zero distance (to avoid division by zero) 75 | valid_galaxies = dist_los > 0.0 76 | 77 | # If no valid galaxies, create an empty plot 78 | if not np.any(valid_galaxies): 79 | print("No galaxies found with valid positions") 80 | # Create an empty plot with a message 81 | ax.text( 82 | 0.5, 83 | 0.5, 84 | "No galaxies found with valid positions", 85 | horizontalalignment="center", 86 | verticalalignment="center", 87 | transform=ax.transAxes, 88 | fontsize=IN_FIGURE_TEXT_SIZE, 89 | ) 90 | 91 | # Save the figure 92 | os.makedirs(output_dir, exist_ok=True) 93 | output_path = os.path.join(output_dir, f"VelocityDistribution{output_format}") 94 | plt.savefig(output_path) 95 | plt.close() 96 | return output_path 97 | 98 | # Get line-of-sight velocity: v·r/|r| (projection of velocity onto position) 99 | pos_x = pos_x[valid_galaxies] 100 | pos_y = pos_y[valid_galaxies] 101 | pos_z = pos_z[valid_galaxies] 102 | vel_x = vel_x[valid_galaxies] 103 | vel_y = vel_y[valid_galaxies] 104 | vel_z = vel_z[valid_galaxies] 105 | dist_los = dist_los[valid_galaxies] 106 | 107 | # Line-of-sight velocity 108 | vel_los = (pos_x * vel_x + pos_y * vel_y + pos_z * vel_z) / dist_los 109 | 110 | # Distance including redshift: r + v/(H*100) 111 | # (standard approach for mock catalogs) 112 | dist_redshift = dist_los + vel_los / (hubble_h * 100.0) 113 | 114 | # Total number of galaxies for normalizing 115 | tot_gals = len(pos_x) 116 | 117 | # Print some debug information 118 | # Print some debug information if verbose mode is enabled 119 | if verbose: 120 | print(f" Number of galaxies: {tot_gals}") 121 | print( 122 | f" Line-of-sight velocity range: {min(vel_los):.2f} to {max(vel_los):.2f} km/s" 123 | ) 124 | print(f" X velocity range: {min(vel_x):.2f} to {max(vel_x):.2f} km/s") 125 | 126 | # Create histograms for each velocity component 127 | # Line-of-sight velocity 128 | counts_los, binedges = np.histogram( 129 | vel_los / (hubble_h * 100.0), range=(bin_min, bin_max), bins=nbins 130 | ) 131 | bin_centers = binedges[:-1] + bin_width / 2 132 | ax.plot( 133 | bin_centers, 134 | counts_los / bin_width / tot_gals, 135 | "k-", 136 | lw=2, 137 | label="line-of-sight", 138 | ) 139 | 140 | # X velocity component 141 | counts_x, _ = np.histogram( 142 | vel_x / (hubble_h * 100.0), range=(bin_min, bin_max), bins=nbins 143 | ) 144 | ax.plot( 145 | bin_centers, counts_x / bin_width / tot_gals, "r-", lw=1.5, label="x-velocity" 146 | ) 147 | 148 | # Y velocity component 149 | counts_y, _ = np.histogram( 150 | vel_y / (hubble_h * 100.0), range=(bin_min, bin_max), bins=nbins 151 | ) 152 | ax.plot( 153 | bin_centers, counts_y / bin_width / tot_gals, "g-", lw=1.5, label="y-velocity" 154 | ) 155 | 156 | # Z velocity component 157 | counts_z, _ = np.histogram( 158 | vel_z / (hubble_h * 100.0), range=(bin_min, bin_max), bins=nbins 159 | ) 160 | ax.plot( 161 | bin_centers, counts_z / bin_width / tot_gals, "b-", lw=1.5, label="z-velocity" 162 | ) 163 | 164 | # Use log scale for y-axis 165 | ax.set_yscale("log") 166 | 167 | # Customize the plot 168 | ax.set_xlabel(r"Velocity / H$_0$", fontsize=AXIS_LABEL_SIZE) 169 | ax.set_ylabel(r"Box Normalised Count", fontsize=AXIS_LABEL_SIZE) 170 | 171 | # Set the x and y axis minor ticks 172 | ax.xaxis.set_minor_locator(MultipleLocator(5)) 173 | 174 | # Set axis limits 175 | ax.set_xlim(bin_min, bin_max) 176 | ax.set_ylim(1e-5, 0.5) 177 | 178 | # Add consistently styled legend 179 | setup_legend(ax, loc="upper left") 180 | 181 | # Save the figure, ensuring the output directory exists 182 | try: 183 | os.makedirs(output_dir, exist_ok=True) 184 | except Exception as e: 185 | print(f"Warning: Could not create output directory {output_dir}: {e}") 186 | # Try to use a subdirectory of the current directory as fallback 187 | output_dir = "./plots" 188 | os.makedirs(output_dir, exist_ok=True) 189 | 190 | output_path = os.path.join(output_dir, f"VelocityDistribution{output_format}") 191 | if verbose: 192 | print(f"Saving Velocity Distribution plot to: {output_path}") 193 | plt.savefig(output_path) 194 | plt.close() 195 | 196 | return output_path 197 | -------------------------------------------------------------------------------- /output/sage-plot/figures/metallicity.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | SAGE Metallicity Plot 5 | 6 | This module generates a plot showing the gas-phase metallicity vs. stellar mass for SAGE galaxy data. 7 | """ 8 | 9 | import os 10 | import random 11 | 12 | import matplotlib.pyplot as plt 13 | import numpy as np 14 | from figures import ( 15 | AXIS_LABEL_SIZE, 16 | IN_FIGURE_TEXT_SIZE, 17 | LEGEND_FONT_SIZE, 18 | get_stellar_mass_label, 19 | setup_legend, 20 | setup_plot_fonts, 21 | ) 22 | from matplotlib.ticker import MultipleLocator 23 | 24 | 25 | def plot( 26 | galaxies, 27 | volume, 28 | metadata, 29 | params, 30 | output_dir="plots", 31 | output_format=".png", 32 | verbose=False, 33 | ): 34 | """ 35 | Create a metallicity vs. stellar mass plot. 36 | 37 | Args: 38 | galaxies: Galaxy data as a numpy recarray 39 | volume: Simulation volume in (Mpc/h)^3 40 | metadata: Dictionary with additional metadata 41 | params: Dictionary with SAGE parameters 42 | output_dir: Output directory for the plot 43 | output_format: File format for the output 44 | 45 | Returns: 46 | Path to the saved plot file 47 | """ 48 | # Set random seed for reproducibility when sampling points 49 | random.seed(2222) 50 | 51 | # Set up the figure 52 | fig, ax = plt.subplots(figsize=(8, 6)) 53 | 54 | # Apply consistent font settings 55 | setup_plot_fonts(ax) 56 | 57 | # Extract necessary metadata 58 | hubble_h = metadata["hubble_h"] 59 | 60 | # Get WhichIMF from parameters 61 | whichimf = 1 # Default to Chabrier IMF 62 | if params: 63 | if "WhichIMF" in params: 64 | whichimf = int(params["WhichIMF"]) 65 | elif "IMF_Type" in params: 66 | whichimf = int(params["IMF_Type"]) 67 | 68 | # Maximum number of points to plot (for better performance and readability) 69 | dilute = 7500 70 | 71 | # First filter for valid mass values - avoid division by zero 72 | valid_mass = ( 73 | (galaxies.Type == 0) 74 | & (galaxies.StellarMass > 0.01) 75 | & (galaxies.ColdGas > 0.0) 76 | & (galaxies.MetalsColdGas > 0.0) 77 | ) 78 | 79 | # Calculate gas fraction safely for valid galaxies 80 | gas_fraction = np.zeros_like(galaxies.StellarMass) 81 | gas_fraction[valid_mass] = galaxies.ColdGas[valid_mass] / ( 82 | galaxies.StellarMass[valid_mass] + galaxies.ColdGas[valid_mass] 83 | ) 84 | 85 | # Now apply all filters 86 | w = np.where(valid_mass & (gas_fraction > 0.1))[0] 87 | 88 | # Check if we have any galaxies to plot 89 | if len(w) == 0: 90 | print("No suitable galaxies found for metallicity plot") 91 | # Create an empty plot with a message 92 | ax.text( 93 | 0.5, 94 | 0.5, 95 | "No suitable galaxies found for metallicity plot", 96 | horizontalalignment="center", 97 | verticalalignment="center", 98 | transform=ax.transAxes, 99 | fontsize=IN_FIGURE_TEXT_SIZE, 100 | ) 101 | 102 | # Save the figure 103 | os.makedirs(output_dir, exist_ok=True) 104 | output_path = os.path.join(output_dir, f"Metallicity{output_format}") 105 | plt.savefig(output_path) 106 | plt.close() 107 | return output_path 108 | 109 | # If we have too many galaxies, randomly sample a subset 110 | if len(w) > dilute: 111 | w = random.sample(list(w), dilute) 112 | 113 | # Calculate metallicity (12 + log10[O/H]) and convert stellar mass to log scale 114 | stellar_mass = np.log10(galaxies.StellarMass[w] * 1.0e10 / hubble_h) 115 | # Metallicity in units of solar (Z_solar = 0.02) 116 | metallicity = ( 117 | np.log10((galaxies.MetalsColdGas[w] / galaxies.ColdGas[w]) / 0.02) + 9.0 118 | ) 119 | 120 | # Print some debug information if verbose mode is enabled 121 | if verbose: 122 | print(f"Metallicity plot debug:") 123 | print(f" Number of galaxies plotted: {len(w)}") 124 | print( 125 | f" Stellar mass range: {min(stellar_mass):.2f} to {max(stellar_mass):.2f}" 126 | ) 127 | print(f" Metallicity range: {min(metallicity):.3f} to {max(metallicity):.3f}") 128 | print(f" WhichIMF: {whichimf}") 129 | 130 | # Plot the galaxy data 131 | ax.scatter( 132 | stellar_mass, 133 | metallicity, 134 | marker="o", 135 | s=1, 136 | c="k", 137 | alpha=0.5, 138 | label="Model galaxies", 139 | ) 140 | 141 | # Add Tremonti et al. 2003 observational relation 142 | # Relation: 12 + log(O/H) = -1.492 + 1.847*log(M*) - 0.08026*log(M*)^2 143 | # Original relation is for Kroupa IMF, need to convert 144 | mass_range = np.arange(7.0, 13.0, 0.1) 145 | tremonti_Z = -1.492 + 1.847 * mass_range - 0.08026 * mass_range * mass_range 146 | 147 | if whichimf == 0: 148 | # Convert from Kroupa IMF to Salpeter IMF (+0.176 dex) 149 | adjusted_mass = np.log10((10**mass_range) * 1.5) 150 | ax.plot(adjusted_mass, tremonti_Z, "b-", lw=2.0, label="Tremonti et al. 2003") 151 | elif whichimf == 1: 152 | # Convert from Kroupa IMF to Chabrier IMF (+0.176 dex, then -0.26 dex) 153 | adjusted_mass = np.log10((10**mass_range) * 1.5 / 1.8) 154 | ax.plot(adjusted_mass, tremonti_Z, "b-", lw=2.0, label="Tremonti et al. 2003") 155 | 156 | # Customize the plot 157 | ax.set_xlabel(get_stellar_mass_label(), fontsize=AXIS_LABEL_SIZE) 158 | ax.set_ylabel(r"12 + log$_{10}$[O/H]", fontsize=AXIS_LABEL_SIZE) 159 | 160 | # Set the x and y axis minor ticks 161 | ax.xaxis.set_minor_locator(MultipleLocator(0.5)) 162 | ax.yaxis.set_minor_locator(MultipleLocator(0.1)) 163 | 164 | # Set axis limits - matching the original plot 165 | ax.set_xlim(8.0, 12.0) 166 | ax.set_ylim(8.0, 9.5) 167 | 168 | # Add consistently styled legend 169 | setup_legend(ax, loc="lower right") 170 | 171 | # Save the figure, ensuring the output directory exists 172 | try: 173 | os.makedirs(output_dir, exist_ok=True) 174 | except Exception as e: 175 | print(f"Warning: Could not create output directory {output_dir}: {e}") 176 | # Try to use a subdirectory of the current directory as fallback 177 | output_dir = "./plots" 178 | os.makedirs(output_dir, exist_ok=True) 179 | 180 | output_path = os.path.join(output_dir, f"Metallicity{output_format}") 181 | if verbose: 182 | print(f"Saving Metallicity plot to: {output_path}") 183 | plt.savefig(output_path) 184 | plt.close() 185 | 186 | return output_path 187 | -------------------------------------------------------------------------------- /code/model_disk_instability.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file model_disk_instability.c 3 | * @brief Implementation of disk instability detection and response 4 | * 5 | * This file implements the model for disk instability in galaxies, which occurs 6 | * when the self-gravity of a galactic disk dominates over the gravitational 7 | * support from the dark matter halo. When instability is detected, mass is 8 | * transferred from the disk to the bulge to restore stability. 9 | * 10 | * The stability criterion follows Mo, Mao & White (1998), comparing the disk 11 | * mass to a critical mass dependent on the maximum circular velocity and disk 12 | * scale radius. When the disk mass exceeds this critical value, the excess 13 | * mass (both stars and gas) is transferred to the bulge, with the gas 14 | * component triggering a starburst and potential black hole growth. 15 | * 16 | * Reference: 17 | * - Mo, Mao & White (1998) for disk stability criterion 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "core_allvars.h" 27 | #include "core_proto.h" 28 | #include "util_numeric.h" 29 | 30 | /** 31 | * @brief Checks for disk instability and transfers mass to restore stability 32 | * 33 | * @param p Index of the galaxy in the Gal array 34 | * @param centralgal Index of the central galaxy 35 | * @param halonr Index of the current halo 36 | * @param time Current time in the simulation 37 | * @param dt Time step size 38 | * @param step Current substep in the time integration 39 | * 40 | * This function evaluates the stability of galactic disks using the criterion 41 | * from Mo, Mao & White (1998). If a disk is found to be unstable, the excess 42 | * mass is transferred to the bulge component: 43 | * 44 | * 1. Stellar disk mass goes directly to the stellar bulge 45 | * 2. Cold gas triggers a starburst (forming stars that go to the bulge) 46 | * 3. If AGN is enabled, some gas can fuel black hole growth 47 | * 48 | * The stability criterion compares the disk mass to a critical mass: 49 | * Mcrit = Vmax^2 * (3 * DiskScaleRadius) / G 50 | * 51 | * The function maintains appropriate tracking of metals during all transfers. 52 | */ 53 | void check_disk_instability(int p, int centralgal, int halonr, double time, 54 | double dt, int step) { 55 | double Mcrit, gas_fraction, unstable_gas, unstable_gas_fraction, 56 | unstable_stars, diskmass, metallicity; 57 | double star_fraction; 58 | 59 | /* Calculate the stability of the stellar and gaseous disk following Mo, Mao & 60 | * White (1998). For unstable stars and gas, we transfer the required amount 61 | * to the bulge to restore stability */ 62 | 63 | /* Calculate total disk mass (cold gas + stellar disk) */ 64 | diskmass = Gal[p].ColdGas + (Gal[p].StellarMass - Gal[p].BulgeMass); 65 | 66 | /* Only proceed if disk mass is positive */ 67 | if (is_greater(diskmass, 0.0)) { 68 | /* Calculate critical disk mass for stability: 69 | * Mcrit = Vmax^2 * (3 * DiskScaleRadius) / G 70 | * This is derived from requiring that the disk's self-gravity doesn't 71 | * dominate */ 72 | Mcrit = Gal[p].Vmax * Gal[p].Vmax * (3.0 * Gal[p].DiskScaleRadius) / G; 73 | 74 | /* Limit critical mass to actual disk mass (can't have negative unstable 75 | * mass) */ 76 | if (Mcrit > diskmass) 77 | Mcrit = diskmass; 78 | 79 | /* Calculate the fractions of gas and stars in the disk */ 80 | gas_fraction = safe_div(Gal[p].ColdGas, diskmass, 0.0); 81 | star_fraction = 1.0 - gas_fraction; 82 | 83 | /* Calculate unstable gas and stellar masses that need to be transferred */ 84 | unstable_gas = gas_fraction * (diskmass - Mcrit); 85 | unstable_stars = star_fraction * (diskmass - Mcrit); 86 | 87 | /* Handle unstable stars - transfer directly to the bulge */ 88 | if (is_greater(unstable_stars, 0.0)) { 89 | /* Calculate disk stellar metallicity (excluding existing bulge) */ 90 | metallicity = 91 | get_metallicity(Gal[p].StellarMass - Gal[p].BulgeMass, 92 | Gal[p].MetalsStellarMass - Gal[p].MetalsBulgeMass); 93 | 94 | /* Add unstable stars to the bulge, preserving metallicity */ 95 | Gal[p].BulgeMass += unstable_stars; 96 | Gal[p].MetalsBulgeMass += metallicity * unstable_stars; 97 | 98 | /* Merge tracking code commented out in original 99 | * Need to fix this. Excluded for now. */ 100 | // Gal[p].mergeType = 3; // mark as disk instability partial mass 101 | // transfer Gal[p].mergeIntoID = NumGals + p - 1; 102 | 103 | /* Sanity check to ensure bulge mass doesn't exceed total stellar mass */ 104 | if (is_greater( 105 | safe_div(Gal[p].BulgeMass, Gal[p].StellarMass, EPSILON_SMALL), 106 | 1.0001) || 107 | is_greater(safe_div(Gal[p].MetalsBulgeMass, Gal[p].MetalsStellarMass, 108 | EPSILON_SMALL), 109 | 1.0001)) { 110 | WARNING_LOG( 111 | "Disk instability caused bulge mass to exceed total stellar mass " 112 | "in galaxy %d. Bulge/Total = %.4f (stars) or %.4f (metals)", 113 | p, Gal[p].BulgeMass / Gal[p].StellarMass, 114 | Gal[p].MetalsBulgeMass / Gal[p].MetalsStellarMass); 115 | // ABORT(0); /* Error checking disabled in original */ 116 | } 117 | } 118 | 119 | /* Handle unstable gas - trigger starburst and black hole growth */ 120 | if (is_greater(unstable_gas, 0.0)) { 121 | /* Sanity check to ensure unstable gas doesn't exceed available cold gas 122 | */ 123 | if (is_greater(safe_div(unstable_gas, Gal[p].ColdGas, EPSILON_SMALL), 124 | 1.0001)) { 125 | WARNING_LOG( 126 | "Disk instability calculation produced unstable gas mass exceeding " 127 | "total cold gas in galaxy %d. Unstable gas = %.4e, Cold gas = %.4e", 128 | p, unstable_gas, Gal[p].ColdGas); 129 | // ABORT(0); /* Error checking disabled in original */ 130 | } 131 | 132 | /* Calculate fraction of cold gas that is unstable */ 133 | unstable_gas_fraction = safe_div(unstable_gas, Gal[p].ColdGas, 0.0); 134 | 135 | /* Feed black hole if AGN recipe is enabled */ 136 | if (SageConfig.AGNrecipeOn > 0) 137 | grow_black_hole(p, unstable_gas_fraction); 138 | 139 | /* Trigger a starburst with the unstable gas 140 | * Mode 1 indicates the burst is due to disk instability */ 141 | collisional_starburst_recipe(unstable_gas_fraction, p, centralgal, time, 142 | dt, halonr, 1, step); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /output/sage-plot/figures/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | SAGE Figure Modules 3 | 4 | This package contains self-contained modules for creating various plots from SAGE galaxy data. 5 | """ 6 | 7 | # Standard figure settings for consistent appearance 8 | """Standard figure settings for consistent appearance across all plots.""" 9 | AXIS_LABEL_SIZE = 16 # Font size for axis labels 10 | TICK_LABEL_SIZE = 12 # Font size for tick labels 11 | LEGEND_FONT_SIZE = 12 # Size for legend text (use numeric size instead of 'large') 12 | IN_FIGURE_TEXT_SIZE = 12 # Size for text inside figures (annotations, etc.) 13 | 14 | 15 | def setup_plot_fonts(ax): 16 | """Apply consistent font sizes to a plot.""" 17 | # Increase tick label sizes 18 | ax.tick_params(axis="both", which="major", labelsize=TICK_LABEL_SIZE) 19 | ax.tick_params(axis="both", which="minor", labelsize=TICK_LABEL_SIZE) 20 | 21 | # Configure global font sizes 22 | import matplotlib.pyplot as plt 23 | 24 | plt.rcParams.update( 25 | { 26 | "font.size": TICK_LABEL_SIZE, 27 | "legend.fontsize": LEGEND_FONT_SIZE, 28 | "figure.titlesize": AXIS_LABEL_SIZE, 29 | } 30 | ) 31 | 32 | # Make sure all labels in legends will use the same font size 33 | import matplotlib as mpl 34 | 35 | mpl.rcParams["legend.fontsize"] = LEGEND_FONT_SIZE 36 | 37 | return ax 38 | 39 | 40 | def setup_legend(ax, loc="best", frameon=False): 41 | """Create a consistently styled legend.""" 42 | leg = ax.legend(loc=loc, numpoints=1, labelspacing=0.1, frameon=frameon) 43 | for t in leg.get_texts(): 44 | t.set_fontsize(LEGEND_FONT_SIZE) 45 | return leg 46 | 47 | 48 | # Utility functions for consistent LaTeX-free labels 49 | def get_mass_function_labels(): 50 | """Return consistent axis labels for mass function plots.""" 51 | y_label = r"$\phi$ (Mpc$^{-3}$ dex$^{-1}$)" 52 | return y_label 53 | 54 | 55 | def get_stellar_mass_label(): 56 | """Return consistent x-axis label for stellar mass plots.""" 57 | x_label = r"log$_{10}$ M$_{\rm stars}$ (M$_{\odot}$)" 58 | return x_label 59 | 60 | 61 | def get_baryonic_mass_label(): 62 | """Return consistent x-axis label for baryonic mass plots.""" 63 | x_label = r"log$_{10}$ M$_{\rm bar}$ (M$_{\odot}$)" 64 | return x_label 65 | 66 | 67 | def get_gas_mass_label(): 68 | """Return consistent x-axis label for gas mass plots.""" 69 | x_label = r"log$_{10}$ M$_{\rm X}$ (M$_{\odot}$)" 70 | return x_label 71 | 72 | 73 | def get_redshift_label(): 74 | """Return consistent x-axis label for redshift plots.""" 75 | x_label = r"redshift" 76 | return x_label 77 | 78 | 79 | def get_sfr_density_label(): 80 | """Return consistent y-axis label for SFR density plots.""" 81 | y_label = r"log$_{10}$ SFR density (M$_{\odot}$ yr$^{-1}$ Mpc$^{-3}$)" 82 | return y_label 83 | 84 | 85 | def get_ssfr_label(): 86 | """Return consistent y-axis label for specific SFR plots.""" 87 | y_label = r"log$_{10}$ sSFR (yr$^{-1}$)" 88 | return y_label 89 | 90 | 91 | def get_vmax_label(): 92 | """Return consistent x-axis label for Vmax plots.""" 93 | x_label = r"log$_{10}$ V$_{\rm max}$ (km/s)" 94 | return x_label 95 | 96 | 97 | def get_black_hole_mass_label(): 98 | """Return consistent x-axis label for black hole mass plots.""" 99 | x_label = r"log$_{10}$ M$_{\rm BH}$ (M$_{\odot}$)" 100 | return x_label 101 | 102 | 103 | def get_bulge_mass_label(): 104 | """Return consistent x-axis label for bulge mass plots.""" 105 | x_label = r"log$_{10}$ M$_{\rm bulge}$ (M$_{\odot}$)" 106 | return x_label 107 | 108 | 109 | def get_halo_mass_label(): 110 | """Return consistent x-axis label for halo mass plots.""" 111 | x_label = r"log$_{10}$ M$_{\rm halo}$ (M$_{\odot}$)" 112 | return x_label 113 | 114 | 115 | def get_spin_parameter_label(): 116 | """Return consistent x-axis label for spin parameter plots.""" 117 | x_label = r"Spin Parameter" 118 | return x_label 119 | 120 | 121 | # Import all the figure modules so they can be discovered 122 | from . import ( 123 | baryon_fraction, 124 | baryonic_mass_function, 125 | baryonic_tully_fisher, 126 | black_hole_bulge_relation, 127 | bulge_mass_fraction, 128 | gas_fraction, 129 | gas_mass_function, 130 | halo_mass_function, 131 | halo_occupation, 132 | hmf_evolution, 133 | mass_reservoir_scatter, 134 | metallicity, 135 | quiescent_fraction, 136 | sfr_density_evolution, 137 | smf_evolution, 138 | spatial_distribution, 139 | specific_sfr, 140 | spin_distribution, 141 | stellar_mass_density_evolution, 142 | stellar_mass_function, 143 | velocity_distribution, 144 | ) 145 | 146 | # Define available plot types 147 | """List of all available snapshot plot modules.""" 148 | SNAPSHOT_PLOTS = [ 149 | "stellar_mass_function", 150 | "baryonic_mass_function", 151 | "gas_mass_function", 152 | "halo_mass_function", 153 | "baryonic_tully_fisher", 154 | "specific_sfr", 155 | "black_hole_bulge_relation", 156 | "gas_fraction", 157 | "metallicity", 158 | "bulge_mass_fraction", 159 | "quiescent_fraction", 160 | "halo_occupation", 161 | "baryon_fraction", 162 | "spin_distribution", 163 | "velocity_distribution", 164 | "mass_reservoir_scatter", 165 | "spatial_distribution", 166 | ] 167 | 168 | """List of all available evolution plot modules.""" 169 | EVOLUTION_PLOTS = [ 170 | "smf_evolution", 171 | "hmf_evolution", 172 | "sfr_density_evolution", 173 | "stellar_mass_density_evolution", 174 | ] 175 | 176 | # Make sure this dictionary matches the classifications above 177 | 178 | """Mapping of plot names to their corresponding functions.""" 179 | PLOT_FUNCS = { 180 | "stellar_mass_function": stellar_mass_function.plot, 181 | "baryonic_mass_function": baryonic_mass_function.plot, 182 | "gas_mass_function": gas_mass_function.plot, 183 | "halo_mass_function": halo_mass_function.plot, 184 | "baryonic_tully_fisher": baryonic_tully_fisher.plot, 185 | "specific_sfr": specific_sfr.plot, 186 | "smf_evolution": smf_evolution.plot, 187 | "hmf_evolution": hmf_evolution.plot, 188 | "sfr_density_evolution": sfr_density_evolution.plot, 189 | "stellar_mass_density_evolution": stellar_mass_density_evolution.plot, 190 | "black_hole_bulge_relation": black_hole_bulge_relation.plot, 191 | "gas_fraction": gas_fraction.plot, 192 | "metallicity": metallicity.plot, 193 | "bulge_mass_fraction": bulge_mass_fraction.plot, 194 | "quiescent_fraction": quiescent_fraction.plot, 195 | "halo_occupation": halo_occupation.plot, 196 | "baryon_fraction": baryon_fraction.plot, 197 | "spin_distribution": spin_distribution.plot, 198 | "velocity_distribution": velocity_distribution.plot, 199 | "mass_reservoir_scatter": mass_reservoir_scatter.plot, 200 | "spatial_distribution": spatial_distribution.plot, 201 | } 202 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_m+05.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0711 1.000 1.103 -22.98 -21.88 -11.51 10.29 2.055 2.486 9.092 2.117 2 | 4.05 0.0711 1.000 1.103 -22.98 -21.88 -11.51 10.29 2.055 2.486 9.092 2.117 3 | 4.10 0.0711 1.000 1.103 -22.98 -21.88 -11.51 10.29 2.055 2.486 9.092 2.117 4 | 4.15 0.2547 1.000 1.103 -22.26 -21.71 -11.40 10.17 2.666 2.486 10.36 1.831 5 | 4.20 0.5700 1.000 1.103 -21.80 -21.60 -11.26 10.11 3.686 2.486 12.18 1.486 6 | 4.25 0.8202 1.000 1.103 -21.64 -21.60 -11.15 10.16 4.755 2.486 13.83 1.293 7 | 4.30 0.9356 1.000 1.103 -21.61 -21.62 -11.07 10.24 5.655 2.487 15.08 1.220 8 | 4.35 0.9812 1.000 1.103 -21.57 -21.60 -11.01 10.27 6.487 2.487 16.15 1.193 9 | 4.40 1.008 1.000 1.103 -21.48 -21.53 -10.96 10.24 7.371 2.487 17.22 1.178 10 | 4.45 1.039 1.000 1.103 -21.36 -21.42 -10.90 10.19 8.393 2.487 18.37 1.161 11 | 4.50 1.071 1.000 1.103 -21.22 -21.30 -10.85 10.11 9.559 2.487 19.61 1.144 12 | 4.55 1.090 1.000 1.103 -21.09 -21.17 -10.79 10.04 10.82 2.487 20.86 1.134 13 | 4.60 1.098 1.000 1.103 -20.97 -21.05 -10.74 9.969 12.19 2.487 22.14 1.130 14 | 4.65 1.102 1.000 1.103 -20.86 -20.94 -10.69 9.911 13.69 2.487 23.47 1.128 15 | 4.70 1.104 1.000 1.103 -20.75 -20.83 -10.64 9.852 15.38 2.487 24.87 1.127 16 | 4.75 1.107 1.000 1.103 -20.65 -20.74 -10.59 9.803 17.28 2.487 26.36 1.125 17 | 4.80 1.116 1.000 1.103 -20.57 -20.66 -10.54 9.776 19.46 2.487 27.98 1.121 18 | 4.85 1.134 1.000 1.103 -20.50 -20.59 -10.48 9.763 22.02 2.487 29.76 1.112 19 | 4.90 1.160 1.000 1.103 -20.43 -20.54 -10.43 9.753 25.00 2.487 31.71 1.099 20 | 4.95 1.183 1.000 1.103 -20.39 -20.50 -10.37 9.772 28.33 2.487 33.75 1.088 21 | 5.00 1.197 1.000 1.103 -20.39 -20.51 -10.32 9.827 31.97 2.487 35.86 1.082 22 | 5.05 1.204 1.000 1.103 -20.42 -20.54 -10.27 9.909 35.99 2.487 38.04 1.078 23 | 5.10 1.208 1.000 1.103 -20.42 -20.55 -10.22 9.961 40.44 2.487 40.33 1.076 24 | 5.15 1.210 1.000 1.103 -20.40 -20.52 -10.17 9.992 45.42 2.487 42.74 1.075 25 | 5.20 1.211 1.000 1.103 -20.37 -20.49 -10.12 10.01 50.99 2.487 45.28 1.075 26 | 5.25 1.212 1.000 1.103 -20.35 -20.48 -10.07 10.04 57.24 2.487 47.98 1.074 27 | 5.30 1.213 1.000 1.103 -20.34 -20.47 -10.02 10.08 64.26 2.487 50.83 1.074 28 | 5.35 1.215 1.000 1.103 -20.34 -20.46 -9.969 10.13 72.14 2.487 53.86 1.073 29 | 5.40 1.216 1.000 1.103 -20.37 -20.50 -9.919 10.21 81.00 2.487 57.07 1.072 30 | 5.45 1.219 1.000 1.103 -20.51 -20.63 -9.868 10.40 90.97 2.487 60.48 1.071 31 | 5.50 1.221 1.000 1.103 -20.73 -20.86 -9.818 10.68 102.20 2.487 64.09 1.070 32 | 5.55 1.221 1.000 1.103 -20.93 -21.06 -9.768 10.93 114.70 2.487 67.91 1.070 33 | 5.60 1.222 1.000 1.103 -21.05 -21.18 -9.717 11.10 128.70 2.487 71.94 1.070 34 | 5.65 1.222 1.000 1.103 -21.09 -21.22 -9.667 11.19 144.4 2.487 76.21 1.069 35 | 5.70 1.223 1.000 1.103 -21.09 -21.22 -9.617 11.24 162.1 2.487 80.73 1.069 36 | 5.75 1.223 1.000 1.103 -21.09 -21.22 -9.567 11.29 181.9 2.487 85.52 1.069 37 | 5.80 1.224 1.000 1.103 -21.14 -21.27 -9.517 11.39 204.1 2.487 90.60 1.069 38 | 5.85 1.224 1.000 1.103 -21.24 -21.38 -9.467 11.54 229.1 2.487 95.98 1.069 39 | 5.90 1.225 1.000 1.103 -21.32 -21.45 -9.417 11.67 257.1 2.487 101.70 1.068 40 | 5.95 1.226 1.000 1.103 -21.34 -21.47 -9.367 11.74 288.5 2.487 107.7 1.068 41 | 6.00 1.226 1.000 1.103 -21.35 -21.48 -9.317 11.80 323.8 2.487 114.1 1.068 42 | 6.05 1.227 1.000 1.103 -21.35 -21.48 -9.266 11.85 363.4 2.487 120.9 1.067 43 | 6.10 1.227 1.000 1.103 -21.34 -21.47 -9.216 11.89 407.9 2.487 128.1 1.067 44 | 6.15 1.228 1.000 1.103 -21.33 -21.46 -9.166 11.93 457.9 2.487 135.7 1.067 45 | 6.20 1.229 1.000 1.103 -21.32 -21.46 -9.116 11.97 513.9 2.487 143.8 1.066 46 | 6.25 1.230 1.000 1.103 -21.35 -21.49 -9.066 12.05 576.8 2.487 152.3 1.066 47 | 6.30 1.231 1.000 1.103 -21.46 -21.59 -9.016 12.21 647.5 2.487 161.4 1.066 48 | 6.35 1.232 1.000 1.103 -21.59 -21.73 -8.966 12.39 726.8 2.487 171.0 1.065 49 | 6.40 1.233 1.000 1.103 -21.71 -21.85 -8.915 12.56 815.8 2.487 181.1 1.065 50 | 6.45 1.234 1.000 1.103 -21.80 -21.94 -8.865 12.70 915.7 2.487 191.9 1.064 51 | 6.50 1.234 1.000 1.103 -21.86 -22.00 -8.815 12.81 1027.7 2.487 203.3 1.064 52 | 6.55 1.235 1.000 1.103 -21.90 -22.03 -8.765 12.90 1153.3 2.487 215.4 1.064 53 | 6.60 1.235 1.000 1.103 -21.93 -22.07 -8.715 12.98 1294.3 2.487 228.1 1.064 54 | 6.65 1.236 1.000 1.103 -21.96 -22.10 -8.665 13.06 1452.5 2.487 241.7 1.063 55 | 6.70 1.236 1.000 1.103 -22.00 -22.14 -8.615 13.15 1629.9 2.487 256.0 1.063 56 | 6.75 1.236 1.000 1.103 -22.04 -22.17 -8.565 13.24 1829.0 2.487 271.2 1.063 57 | 6.80 1.237 1.000 1.103 -22.06 -22.20 -8.515 13.31 2052.3 2.487 287.3 1.063 58 | 6.85 1.237 1.000 1.103 -22.06 -22.20 -8.465 13.36 2303.0 2.487 304.3 1.063 59 | 6.90 1.237 1.000 1.103 -22.05 -22.18 -8.415 13.40 2584.2 2.487 322.4 1.063 60 | 6.95 1.237 1.000 1.103 -22.04 -22.17 -8.365 13.44 2899.7 2.487 341.5 1.063 61 | 7.00 1.237 1.000 1.103 -22.04 -22.17 -8.315 13.49 3253.8 2.487 361.7 1.063 62 | 7.05 1.237 1.000 1.103 -22.06 -22.20 -8.265 13.56 3651.2 2.487 383.2 1.063 63 | 7.10 1.238 1.000 1.103 -22.11 -22.24 -8.214 13.66 4097.0 2.487 405.9 1.063 64 | 7.15 1.238 1.000 1.103 -22.16 -22.30 -8.164 13.76 4597.2 2.487 430.0 1.062 65 | 7.20 1.238 1.000 1.103 -22.21 -22.35 -8.114 13.86 5158.4 2.487 455.4 1.062 66 | 7.25 1.238 1.000 1.103 -22.26 -22.40 -8.064 13.96 5788.0 2.487 482.4 1.062 67 | 7.30 1.238 1.000 1.103 -22.30 -22.43 -8.014 14.05 6494.4 2.487 511.0 1.062 68 | 7.35 1.238 1.000 1.103 -22.32 -22.46 -7.964 14.12 7287.0 2.487 541.3 1.062 69 | 7.40 1.238 1.000 1.103 -22.35 -22.48 -7.914 14.20 8176.3 2.487 573.4 1.062 70 | 7.45 1.238 1.000 1.103 -22.36 -22.49 -7.864 14.26 9174.0 2.487 607.4 1.062 71 | 7.50 1.238 1.000 1.103 -22.37 -22.50 -7.814 14.32 10293.6 2.487 643.4 1.062 72 | 7.55 1.238 1.000 1.103 -22.37 -22.51 -7.764 14.37 11549.7 2.487 681.5 1.062 73 | 7.60 1.238 1.000 1.103 -22.37 -22.51 -7.714 14.42 12959.1 2.487 721.9 1.062 74 | 7.65 1.238 1.000 1.103 -22.37 -22.51 -7.664 14.47 14540.5 2.487 764.7 1.062 75 | 7.70 1.238 1.000 1.103 -22.37 -22.50 -7.614 14.52 16314.8 2.487 810.0 1.062 76 | 7.75 1.238 1.000 1.103 -22.36 -22.49 -7.564 14.56 18305.7 2.487 858.0 1.062 77 | 7.80 1.238 1.000 1.103 -22.35 -22.48 -7.514 14.60 20539.6 2.487 908.8 1.062 78 | 7.85 1.238 1.000 1.103 -22.34 -22.47 -7.464 14.64 23046.0 2.487 962.7 1.062 79 | 7.90 1.238 1.000 1.103 -22.33 -22.46 -7.414 14.68 25858.3 2.487 1019.7 1.062 80 | 7.95 1.238 1.000 1.103 -22.31 -22.45 -7.364 14.71 29013.8 2.487 1080.1 1.062 81 | 8.00 1.238 1.000 1.103 -22.30 -22.44 -7.314 14.75 32554.3 2.487 1144.2 1.062 82 | 8.05 1.238 1.000 1.103 -22.29 -22.42 -7.264 14.79 36526.9 2.487 1211.9 1.062 83 | 8.10 1.238 1.000 1.103 -22.27 -22.41 -7.214 14.82 40984.2 2.487 1283.8 1.062 84 | 8.15 1.238 1.000 1.103 -22.26 -22.40 -7.164 14.86 45985.4 2.487 1359.8 1.062 85 | 8.20 1.238 1.000 1.103 -22.25 -22.38 -7.114 14.90 51596.8 2.487 1440.4 1.062 86 | 8.25 1.238 1.000 1.103 -22.23 -22.37 -7.064 14.93 57892.9 2.487 1525.8 1.062 87 | 8.30 1.238 1.000 1.103 -22.21 -22.35 -7.014 14.96 64957.3 2.487 1616.2 1.062 88 | 8.35 1.239 1.000 1.103 -22.20 -22.33 -6.964 15.00 72883.6 2.487 1712.0 1.062 89 | 8.40 1.239 1.000 1.103 -22.18 -22.32 -6.914 15.03 81777.0 2.487 1813.4 1.062 90 | 8.45 1.239 1.000 1.103 -22.16 -22.30 -6.864 15.06 91755.6 2.487 1920.9 1.062 91 | 8.50 1.239 1.000 1.103 -22.14 -22.28 -6.814 15.09 102952 2.487 2034.7 1.062 92 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_m-00.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0023 1.000 1.099 -25.65 -23.06 -11.64 11.37 1.532 2.386 8.012 2.166 2 | 4.05 0.0142 1.000 1.099 -24.27 -22.46 -11.59 10.83 1.737 2.386 8.533 2.143 3 | 4.10 0.0704 1.000 1.099 -23.28 -22.17 -11.52 10.58 2.048 2.386 9.264 2.040 4 | 4.15 0.2534 1.000 1.099 -22.47 -21.92 -11.40 10.38 2.657 2.386 10.55 1.764 5 | 4.20 0.5678 1.000 1.099 -21.99 -21.79 -11.26 10.30 3.674 2.387 12.41 1.431 6 | 4.25 0.8177 1.000 1.099 -21.84 -21.80 -11.15 10.36 4.740 2.387 14.09 1.245 7 | 4.30 0.9324 1.000 1.099 -21.85 -21.86 -11.08 10.48 5.637 2.387 15.37 1.175 8 | 4.35 0.9780 1.000 1.099 -21.87 -21.90 -11.02 10.57 6.467 2.387 16.46 1.149 9 | 4.40 1.004 1.000 1.099 -21.84 -21.88 -10.96 10.60 7.347 2.387 17.54 1.135 10 | 4.45 1.035 1.000 1.099 -21.77 -21.82 -10.90 10.59 8.366 2.387 18.72 1.118 11 | 4.50 1.067 1.000 1.099 -21.66 -21.73 -10.85 10.55 9.528 2.387 19.98 1.102 12 | 4.55 1.086 1.000 1.099 -21.56 -21.63 -10.79 10.50 10.78 2.387 21.25 1.092 13 | 4.60 1.094 1.000 1.099 -21.45 -21.53 -10.74 10.45 12.14 2.387 22.56 1.088 14 | 4.65 1.098 1.000 1.099 -21.34 -21.42 -10.69 10.39 13.65 2.387 23.91 1.087 15 | 4.70 1.100 1.000 1.099 -21.24 -21.32 -10.64 10.34 15.32 2.387 25.34 1.086 16 | 4.75 1.102 1.000 1.099 -21.14 -21.22 -10.59 10.29 17.22 2.387 26.86 1.084 17 | 4.80 1.110 1.000 1.099 -21.05 -21.14 -10.54 10.25 19.38 2.387 28.50 1.080 18 | 4.85 1.128 1.000 1.099 -20.97 -21.07 -10.49 10.23 21.92 2.387 30.31 1.072 19 | 4.90 1.154 1.000 1.099 -20.91 -21.01 -10.43 10.23 24.89 2.387 32.29 1.059 20 | 4.95 1.176 1.000 1.099 -20.87 -20.98 -10.38 10.25 28.19 2.387 34.37 1.049 21 | 5.00 1.188 1.000 1.099 -20.87 -20.99 -10.32 10.30 31.81 2.387 36.50 1.043 22 | 5.05 1.195 1.000 1.099 -20.90 -21.02 -10.27 10.38 35.79 2.387 38.72 1.041 23 | 5.10 1.198 1.000 1.099 -20.91 -21.03 -10.22 10.45 40.21 2.387 41.04 1.039 24 | 5.15 1.199 1.000 1.099 -20.89 -21.01 -10.17 10.48 45.14 2.387 43.49 1.039 25 | 5.20 1.200 1.000 1.099 -20.86 -20.98 -10.12 10.50 50.67 2.387 46.07 1.038 26 | 5.25 1.201 1.000 1.099 -20.85 -20.97 -10.07 10.54 56.87 2.387 48.81 1.038 27 | 5.30 1.201 1.000 1.099 -20.84 -20.96 -10.02 10.58 63.82 2.387 51.71 1.038 28 | 5.35 1.201 1.000 1.099 -20.84 -20.96 -9.972 10.63 71.62 2.387 54.78 1.038 29 | 5.40 1.202 1.000 1.099 -20.87 -20.99 -9.922 10.71 80.38 2.387 58.03 1.037 30 | 5.45 1.203 1.000 1.099 -21.01 -21.13 -9.872 10.90 90.22 2.387 61.48 1.037 31 | 5.50 1.203 1.000 1.099 -21.23 -21.35 -9.822 11.17 101.2 2.387 65.13 1.037 32 | 5.55 1.204 1.000 1.099 -21.43 -21.55 -9.772 11.42 113.6 2.387 68.99 1.037 33 | 5.60 1.204 1.000 1.099 -21.54 -21.66 -9.722 11.58 127.5 2.387 73.08 1.036 34 | 5.65 1.204 1.000 1.099 -21.58 -21.71 -9.672 11.67 143.1 2.387 77.41 1.036 35 | 5.70 1.204 1.000 1.099 -21.59 -21.71 -9.622 11.73 160.5 2.387 82.00 1.036 36 | 5.75 1.204 1.000 1.099 -21.59 -21.71 -9.572 11.78 180.1 2.387 86.87 1.036 37 | 5.80 1.204 1.000 1.099 -21.64 -21.76 -9.522 11.88 202.1 2.387 92.02 1.036 38 | 5.85 1.205 1.000 1.099 -21.74 -21.86 -9.471 12.03 226.8 2.387 97.47 1.036 39 | 5.90 1.205 1.000 1.099 -21.81 -21.93 -9.421 12.15 254.5 2.387 103.3 1.036 40 | 5.95 1.205 1.000 1.099 -21.83 -21.95 -9.371 12.22 285.6 2.387 109.4 1.036 41 | 6.00 1.205 1.000 1.099 -21.84 -21.96 -9.321 12.28 320.4 2.387 115.9 1.036 42 | 6.05 1.205 1.000 1.099 -21.84 -21.96 -9.271 12.33 359.6 2.387 122.7 1.036 43 | 6.10 1.206 1.000 1.099 -21.83 -21.96 -9.221 12.37 403.5 2.387 130.0 1.036 44 | 6.15 1.206 1.000 1.099 -21.82 -21.95 -9.171 12.41 452.8 2.387 137.7 1.036 45 | 6.20 1.206 1.000 1.099 -21.82 -21.94 -9.121 12.46 508.1 2.387 145.9 1.035 46 | 6.25 1.206 1.000 1.099 -21.85 -21.97 -9.071 12.54 570.1 2.387 154.5 1.035 47 | 6.30 1.207 1.000 1.099 -21.95 -22.07 -9.021 12.69 639.8 2.387 163.7 1.035 48 | 6.35 1.207 1.000 1.099 -22.08 -22.20 -8.971 12.87 717.9 2.387 173.4 1.035 49 | 6.40 1.207 1.000 1.099 -22.19 -22.31 -8.921 13.03 805.6 2.387 183.7 1.035 50 | 6.45 1.208 1.000 1.099 -22.27 -22.39 -8.871 13.16 904.0 2.387 194.6 1.035 51 | 6.50 1.208 1.000 1.099 -22.32 -22.44 -8.821 13.26 1014.5 2.387 206.1 1.035 52 | 6.55 1.208 1.000 1.099 -22.35 -22.48 -8.771 13.34 1138.3 2.387 218.4 1.035 53 | 6.60 1.208 1.000 1.099 -22.38 -22.50 -8.721 13.42 1277.3 2.387 231.3 1.035 54 | 6.65 1.208 1.000 1.099 -22.41 -22.53 -8.671 13.50 1433.2 2.387 245.0 1.034 55 | 6.70 1.208 1.000 1.099 -22.44 -22.56 -8.621 13.58 1608.2 2.387 259.6 1.034 56 | 6.75 1.208 1.000 1.099 -22.46 -22.59 -8.571 13.65 1804.4 2.387 274.9 1.034 57 | 6.80 1.208 1.000 1.099 -22.48 -22.60 -8.521 13.72 2024.7 2.387 291.2 1.034 58 | 6.85 1.209 1.000 1.099 -22.48 -22.60 -8.471 13.77 2271.8 2.387 308.5 1.034 59 | 6.90 1.209 1.000 1.099 -22.46 -22.59 -8.421 13.80 2549.1 2.387 326.8 1.034 60 | 6.95 1.209 1.000 1.099 -22.45 -22.57 -8.371 13.84 2860.2 2.387 346.1 1.034 61 | 7.00 1.209 1.000 1.099 -22.45 -22.57 -8.321 13.89 3209.2 2.387 366.7 1.034 62 | 7.05 1.209 1.000 1.099 -22.46 -22.59 -8.271 13.95 3600.9 2.387 388.4 1.034 63 | 7.10 1.209 1.000 1.099 -22.49 -22.62 -8.221 14.03 4040.4 2.387 411.4 1.034 64 | 7.15 1.209 1.000 1.099 -22.53 -22.65 -8.171 14.12 4533.5 2.387 435.8 1.034 65 | 7.20 1.209 1.000 1.099 -22.56 -22.68 -8.121 14.20 5086.8 2.387 461.6 1.034 66 | 7.25 1.209 1.000 1.099 -22.58 -22.70 -8.071 14.27 5707.5 2.387 489.0 1.034 67 | 7.30 1.209 1.000 1.099 -22.60 -22.72 -8.021 14.34 6404.0 2.387 518.0 1.034 68 | 7.35 1.209 1.000 1.099 -22.61 -22.73 -7.971 14.40 7185.4 2.387 548.6 1.034 69 | 7.40 1.209 1.000 1.099 -22.61 -22.73 -7.921 14.45 8062.2 2.387 581.2 1.034 70 | 7.45 1.209 1.000 1.099 -22.61 -22.73 -7.871 14.50 9046.0 2.387 615.6 1.034 71 | 7.50 1.209 1.000 1.099 -22.60 -22.73 -7.821 14.54 10149.8 2.387 652.1 1.034 72 | 7.55 1.209 1.000 1.099 -22.60 -22.72 -7.771 14.59 11388.3 2.387 690.7 1.034 73 | 7.60 1.209 1.000 1.099 -22.59 -22.71 -7.721 14.63 12777.9 2.387 731.6 1.034 74 | 7.65 1.209 1.000 1.099 -22.57 -22.70 -7.671 14.66 14337.1 2.387 775.0 1.034 75 | 7.70 1.209 1.000 1.099 -22.56 -22.68 -7.621 14.70 16086.6 2.387 820.9 1.034 76 | 7.75 1.209 1.000 1.099 -22.54 -22.67 -7.571 14.73 18049.5 2.387 869.6 1.034 77 | 7.80 1.209 1.000 1.099 -22.53 -22.65 -7.521 14.77 20251.9 2.387 921.1 1.034 78 | 7.85 1.209 1.000 1.099 -22.51 -22.64 -7.471 14.80 22723.1 2.387 975.7 1.034 79 | 7.90 1.209 1.000 1.099 -22.49 -22.62 -7.421 14.83 25495.8 2.387 1033.5 1.034 80 | 7.95 1.209 1.000 1.099 -22.48 -22.60 -7.371 14.87 28606.9 2.387 1094.7 1.034 81 | 8.00 1.209 1.000 1.099 -22.46 -22.58 -7.321 14.90 32097.6 2.387 1159.6 1.034 82 | 8.05 1.209 1.000 1.099 -22.44 -22.56 -7.271 14.93 36014.2 2.387 1228.3 1.034 83 | 8.10 1.209 1.000 1.099 -22.42 -22.54 -7.221 14.96 40408.7 2.387 1301.1 1.034 84 | 8.15 1.209 1.000 1.099 -22.40 -22.53 -7.171 14.99 45339.4 2.387 1378.2 1.034 85 | 8.20 1.209 1.000 1.099 -22.38 -22.51 -7.121 15.02 50871.7 2.387 1459.8 1.034 86 | 8.25 1.209 1.000 1.099 -22.36 -22.49 -7.071 15.05 57079.1 2.387 1546.3 1.034 87 | 8.30 1.209 1.000 1.099 -22.34 -22.47 -7.021 15.08 64044.0 2.387 1638.0 1.034 88 | 8.35 1.209 1.000 1.099 -22.32 -22.45 -6.971 15.11 71858.6 2.387 1735.0 1.034 89 | 8.40 1.209 1.000 1.099 -22.30 -22.43 -6.921 15.14 80626.8 2.387 1837.8 1.034 90 | 8.45 1.209 1.000 1.099 -22.28 -22.40 -6.871 15.17 90464.8 2.387 1946.7 1.034 91 | 8.50 1.209 1.000 1.099 -22.26 -22.38 -6.821 15.20 101503 2.387 2062.1 1.034 92 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_m-05.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0023 1.000 1.080 -25.83 -23.22 -11.65 11.54 1.505 2.239 8.198 2.069 2 | 4.05 0.0141 1.000 1.080 -24.49 -22.68 -11.59 11.04 1.707 2.239 8.732 2.046 3 | 4.10 0.0703 1.000 1.080 -23.42 -22.30 -11.52 10.72 2.014 2.239 9.483 1.947 4 | 4.15 0.2530 1.000 1.080 -22.56 -22.00 -11.41 10.46 2.619 2.240 10.81 1.680 5 | 4.20 0.5673 1.000 1.080 -22.07 -21.85 -11.27 10.37 3.631 2.240 12.73 1.360 6 | 4.25 0.8162 1.000 1.080 -21.92 -21.86 -11.16 10.43 4.689 2.240 14.47 1.181 7 | 4.30 0.9317 1.000 1.080 -21.94 -21.94 -11.08 10.56 5.582 2.240 15.78 1.113 8 | 4.35 0.9767 1.000 1.080 -22.00 -22.02 -11.02 10.69 6.403 2.240 16.91 1.089 9 | 4.40 1.001 1.000 1.080 -22.02 -22.06 -10.97 10.77 7.269 2.240 18.01 1.076 10 | 4.45 1.027 1.000 1.080 -22.00 -22.05 -10.91 10.81 8.259 2.240 19.20 1.063 11 | 4.50 1.054 1.000 1.080 -21.94 -22.00 -10.85 10.81 9.383 2.240 20.47 1.050 12 | 4.55 1.069 1.000 1.080 -21.87 -21.93 -10.80 10.80 10.61 2.240 21.76 1.042 13 | 4.60 1.076 1.000 1.080 -21.78 -21.85 -10.75 10.76 11.94 2.240 23.08 1.039 14 | 4.65 1.079 1.000 1.080 -21.69 -21.75 -10.70 10.72 13.41 2.240 24.46 1.038 15 | 4.70 1.080 1.000 1.080 -21.59 -21.66 -10.65 10.67 15.05 2.240 25.92 1.037 16 | 4.75 1.082 1.000 1.080 -21.50 -21.57 -10.60 10.63 16.91 2.240 27.47 1.036 17 | 4.80 1.088 1.000 1.080 -21.41 -21.48 -10.55 10.60 19.03 2.240 29.14 1.033 18 | 4.85 1.103 1.000 1.080 -21.33 -21.41 -10.49 10.57 21.49 2.240 30.97 1.026 19 | 4.90 1.124 1.000 1.080 -21.27 -21.35 -10.44 10.57 24.34 2.240 32.96 1.016 20 | 4.95 1.142 1.000 1.080 -21.23 -21.32 -10.39 10.59 27.53 2.240 35.06 1.008 21 | 5.00 1.152 1.000 1.080 -21.22 -21.32 -10.34 10.63 31.04 2.240 37.22 1.004 22 | 5.05 1.157 1.000 1.080 -21.23 -21.33 -10.28 10.69 34.90 2.240 39.47 1.002 23 | 5.10 1.159 1.000 1.080 -21.22 -21.32 -10.23 10.73 39.20 2.240 41.83 1.001 24 | 5.15 1.160 1.000 1.080 -21.19 -21.29 -10.18 10.75 44.00 2.240 44.32 1.000 25 | 5.20 1.161 1.000 1.080 -21.16 -21.26 -10.13 10.77 49.38 2.240 46.95 1.000 26 | 5.25 1.161 1.000 1.080 -21.14 -21.23 -10.08 10.80 55.42 2.240 49.74 1.000 27 | 5.30 1.161 1.000 1.080 -21.12 -21.21 -10.03 10.83 62.19 2.240 52.69 0.999 28 | 5.35 1.162 1.000 1.080 -21.10 -21.20 -9.983 10.86 69.79 2.240 55.81 0.999 29 | 5.40 1.162 1.000 1.080 -21.14 -21.23 -9.933 10.95 78.31 2.240 59.12 0.999 30 | 5.45 1.162 1.000 1.080 -21.27 -21.37 -9.883 11.13 87.88 2.240 62.63 0.999 31 | 5.50 1.163 1.000 1.080 -21.50 -21.60 -9.833 11.42 98.62 2.240 66.35 0.999 32 | 5.55 1.163 1.000 1.080 -21.70 -21.79 -9.783 11.67 110.7 2.240 70.28 0.999 33 | 5.60 1.163 1.000 1.080 -21.81 -21.91 -9.733 11.83 124.2 2.240 74.45 0.999 34 | 5.65 1.163 1.000 1.080 -21.85 -21.95 -9.683 11.92 139.3 2.240 78.86 0.999 35 | 5.70 1.163 1.000 1.080 -21.86 -21.96 -9.633 11.98 156.3 2.240 83.53 0.999 36 | 5.75 1.163 1.000 1.080 -21.87 -21.97 -9.583 12.04 175.4 2.240 88.48 0.999 37 | 5.80 1.163 1.000 1.080 -21.93 -22.03 -9.533 12.15 196.8 2.240 93.73 0.999 38 | 5.85 1.163 1.000 1.080 -22.05 -22.15 -9.483 12.32 220.9 2.240 99.29 0.999 39 | 5.90 1.163 1.000 1.080 -22.15 -22.24 -9.433 12.47 247.8 2.240 105.2 0.999 40 | 5.95 1.164 1.000 1.080 -22.19 -22.29 -9.383 12.56 278.1 2.240 111.4 0.999 41 | 6.00 1.164 1.000 1.080 -22.22 -22.32 -9.333 12.64 312.0 2.240 118.0 0.999 42 | 6.05 1.164 1.000 1.080 -22.24 -22.34 -9.283 12.71 350.1 2.240 125.0 0.998 43 | 6.10 1.164 1.000 1.080 -22.24 -22.34 -9.233 12.76 392.8 2.240 132.4 0.998 44 | 6.15 1.164 1.000 1.080 -22.24 -22.34 -9.183 12.81 440.8 2.240 140.3 0.998 45 | 6.20 1.164 1.000 1.080 -22.23 -22.33 -9.133 12.85 494.6 2.240 148.6 0.998 46 | 6.25 1.164 1.000 1.080 -22.26 -22.36 -9.083 12.93 554.9 2.240 157.4 0.998 47 | 6.30 1.164 1.000 1.080 -22.34 -22.44 -9.033 13.06 622.7 2.240 166.7 0.998 48 | 6.35 1.164 1.000 1.080 -22.44 -22.54 -8.983 13.21 698.7 2.240 176.6 0.998 49 | 6.40 1.164 1.000 1.080 -22.53 -22.63 -8.933 13.35 784.0 2.240 187.1 0.998 50 | 6.45 1.165 1.000 1.080 -22.59 -22.69 -8.883 13.46 879.7 2.240 198.2 0.998 51 | 6.50 1.165 1.000 1.080 -22.64 -22.74 -8.833 13.56 987.1 2.240 209.9 0.998 52 | 6.55 1.165 1.000 1.080 -22.66 -22.76 -8.783 13.63 1107.6 2.240 222.3 0.998 53 | 6.60 1.165 1.000 1.080 -22.69 -22.79 -8.733 13.71 1242.8 2.240 235.5 0.998 54 | 6.65 1.165 1.000 1.080 -22.71 -22.81 -8.683 13.78 1394.5 2.240 249.5 0.998 55 | 6.70 1.165 1.000 1.080 -22.73 -22.83 -8.633 13.85 1564.7 2.240 264.3 0.998 56 | 6.75 1.165 1.000 1.080 -22.75 -22.85 -8.583 13.92 1755.6 2.240 279.9 0.998 57 | 6.80 1.165 1.000 1.080 -22.76 -22.86 -8.533 13.98 1969.9 2.240 296.5 0.998 58 | 6.85 1.165 1.000 1.080 -22.75 -22.85 -8.483 14.02 2210.3 2.240 314.1 0.998 59 | 6.90 1.165 1.000 1.080 -22.74 -22.84 -8.433 14.06 2480.0 2.240 332.7 0.998 60 | 6.95 1.165 1.000 1.080 -22.74 -22.84 -8.383 14.11 2782.6 2.240 352.4 0.998 61 | 7.00 1.165 1.000 1.080 -22.73 -22.83 -8.333 14.15 3122.2 2.240 373.3 0.998 62 | 7.05 1.165 1.000 1.080 -22.73 -22.83 -8.283 14.20 3503.2 2.240 395.4 0.998 63 | 7.10 1.165 1.000 1.080 -22.75 -22.85 -8.233 14.27 3930.7 2.240 418.9 0.998 64 | 7.15 1.165 1.000 1.080 -22.76 -22.86 -8.183 14.33 4410.4 2.240 443.7 0.998 65 | 7.20 1.165 1.000 1.080 -22.77 -22.87 -8.133 14.39 4948.5 2.240 470.0 0.998 66 | 7.25 1.165 1.000 1.080 -22.77 -22.87 -8.083 14.44 5552.4 2.240 497.8 0.998 67 | 7.30 1.165 1.000 1.080 -22.77 -22.87 -8.033 14.49 6229.9 2.240 527.3 0.998 68 | 7.35 1.165 1.000 1.080 -22.76 -22.86 -7.983 14.53 6990.0 2.240 558.6 0.998 69 | 7.40 1.165 1.000 1.080 -22.75 -22.85 -7.933 14.57 7843.0 2.240 591.7 0.998 70 | 7.45 1.165 1.000 1.080 -22.74 -22.84 -7.883 14.61 8800.0 2.240 626.7 0.998 71 | 7.50 1.165 1.000 1.080 -22.73 -22.83 -7.833 14.65 9873.8 2.240 663.9 0.998 72 | 7.55 1.165 1.000 1.080 -22.72 -22.82 -7.783 14.69 11078.6 2.240 703.2 0.998 73 | 7.60 1.165 1.000 1.080 -22.70 -22.80 -7.733 14.72 12430.4 2.240 744.9 0.998 74 | 7.65 1.165 1.000 1.080 -22.68 -22.78 -7.683 14.75 13947.1 2.240 789.0 0.998 75 | 7.70 1.165 1.000 1.080 -22.66 -22.76 -7.633 14.78 15648.9 2.240 835.8 0.998 76 | 7.75 1.165 1.000 1.080 -22.65 -22.75 -7.583 14.82 17558.4 2.240 885.3 0.998 77 | 7.80 1.165 1.000 1.080 -22.63 -22.73 -7.533 14.85 19700.9 2.240 937.7 0.998 78 | 7.85 1.165 1.000 1.080 -22.61 -22.71 -7.483 14.88 22104.8 2.240 993.3 0.998 79 | 7.90 1.165 1.000 1.080 -22.59 -22.69 -7.433 14.91 24802.0 2.240 1052.2 0.998 80 | 7.95 1.165 1.000 1.080 -22.57 -22.67 -7.383 14.94 27828.3 2.240 1114.5 0.998 81 | 8.00 1.165 1.000 1.080 -22.55 -22.65 -7.333 14.97 31223.9 2.240 1180.5 0.998 82 | 8.05 1.165 1.000 1.080 -22.53 -22.63 -7.283 15.00 35033.9 2.240 1250.5 0.998 83 | 8.10 1.165 1.000 1.080 -22.50 -22.60 -7.233 15.02 39308.7 2.240 1324.6 0.998 84 | 8.15 1.165 1.000 1.080 -22.48 -22.58 -7.183 15.05 44105.1 2.240 1403.1 0.998 85 | 8.20 1.165 1.000 1.080 -22.46 -22.56 -7.133 15.08 49486.8 2.240 1486.2 0.998 86 | 8.25 1.165 1.000 1.080 -22.44 -22.54 -7.083 15.11 55525.1 2.240 1574.3 0.998 87 | 8.30 1.165 1.000 1.080 -22.42 -22.52 -7.033 15.14 62300.2 2.240 1667.6 0.998 88 | 8.35 1.165 1.000 1.080 -22.40 -22.50 -6.983 15.17 69902.0 2.240 1766.4 0.998 89 | 8.40 1.165 1.000 1.080 -22.38 -22.48 -6.933 15.20 78431.4 2.240 1871.0 0.998 90 | 8.45 1.165 1.000 1.080 -22.35 -22.45 -6.883 15.22 88001.5 2.240 1981.9 0.998 91 | 8.50 1.165 1.000 1.080 -22.33 -22.43 -6.833 15.25 98739.4 2.240 2099.3 0.998 92 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_m-10.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0022 1.000 1.064 -25.94 -23.31 -11.66 11.63 1.483 2.125 8.354 1.992 2 | 4.05 0.0141 1.000 1.064 -24.61 -22.78 -11.60 11.15 1.683 2.125 8.898 1.971 3 | 4.10 0.0702 1.000 1.064 -23.49 -22.36 -11.53 10.78 1.986 2.125 9.667 1.873 4 | 4.15 0.2529 1.000 1.064 -22.60 -22.03 -11.41 10.50 2.587 2.125 11.03 1.613 5 | 4.20 0.5667 1.000 1.064 -22.10 -21.88 -11.27 10.40 3.595 2.126 13.00 1.303 6 | 4.25 0.8163 1.000 1.064 -21.95 -21.89 -11.16 10.45 4.650 2.126 14.79 1.130 7 | 4.30 0.9312 1.000 1.064 -21.99 -21.98 -11.08 10.60 5.537 2.126 16.14 1.065 8 | 4.35 0.9758 1.000 1.064 -22.07 -22.08 -11.02 10.75 6.351 2.126 17.28 1.042 9 | 4.40 0.9984 1.000 1.064 -22.13 -22.16 -10.97 10.87 7.205 2.126 18.41 1.031 10 | 4.45 1.021 1.000 1.064 -22.15 -22.19 -10.91 10.95 8.172 2.126 19.61 1.020 11 | 4.50 1.043 1.000 1.064 -22.15 -22.19 -10.86 11.01 9.265 2.126 20.88 1.009 12 | 4.55 1.055 1.000 1.064 -22.11 -22.16 -10.81 11.03 10.46 2.126 22.18 1.003 13 | 4.60 1.061 1.000 1.064 -22.06 -22.11 -10.76 11.03 11.76 2.126 23.52 1.000 14 | 4.65 1.063 1.000 1.064 -21.98 -22.04 -10.71 11.00 13.21 2.126 24.93 0.999 15 | 4.70 1.064 1.000 1.064 -21.90 -21.95 -10.66 10.97 14.83 2.126 26.41 0.999 16 | 4.75 1.066 1.000 1.064 -21.81 -21.86 -10.61 10.93 16.66 2.126 27.99 0.998 17 | 4.80 1.071 1.000 1.064 -21.72 -21.77 -10.55 10.89 18.73 2.126 29.68 0.996 18 | 4.85 1.082 1.000 1.064 -21.63 -21.69 -10.50 10.86 21.13 2.126 31.53 0.990 19 | 4.90 1.099 1.000 1.064 -21.57 -21.64 -10.45 10.85 23.90 2.126 33.53 0.983 20 | 4.95 1.114 1.000 1.064 -21.54 -21.61 -10.40 10.88 26.99 2.126 35.63 0.976 21 | 5.00 1.122 1.000 1.064 -21.53 -21.60 -10.34 10.92 30.40 2.126 37.81 0.973 22 | 5.05 1.126 1.000 1.064 -21.52 -21.60 -10.29 10.96 34.17 2.126 40.09 0.971 23 | 5.10 1.127 1.000 1.064 -21.50 -21.58 -10.24 11.00 38.37 2.126 42.48 0.970 24 | 5.15 1.128 1.000 1.064 -21.47 -21.55 -10.19 11.02 43.07 2.126 45.01 0.970 25 | 5.20 1.129 1.000 1.064 -21.44 -21.52 -10.14 11.04 48.33 2.126 47.68 0.969 26 | 5.25 1.129 1.000 1.064 -21.41 -21.49 -10.09 11.06 54.23 2.126 50.51 0.969 27 | 5.30 1.129 1.000 1.064 -21.38 -21.46 -10.04 11.08 60.86 2.126 53.50 0.969 28 | 5.35 1.129 1.000 1.064 -21.36 -21.44 -9.993 11.11 68.29 2.126 56.67 0.969 29 | 5.40 1.129 1.000 1.064 -21.40 -21.48 -9.943 11.20 76.63 2.126 60.03 0.969 30 | 5.45 1.130 1.000 1.064 -21.53 -21.61 -9.893 11.38 85.99 2.126 63.59 0.969 31 | 5.50 1.130 1.000 1.064 -21.75 -21.84 -9.843 11.65 96.49 2.126 67.37 0.969 32 | 5.55 1.130 1.000 1.064 -21.95 -22.03 -9.793 11.90 108.3 2.126 71.36 0.969 33 | 5.60 1.130 1.000 1.064 -22.07 -22.15 -9.743 12.07 121.5 2.126 75.59 0.969 34 | 5.65 1.130 1.000 1.064 -22.11 -22.19 -9.693 12.16 136.3 2.126 80.07 0.969 35 | 5.70 1.130 1.000 1.064 -22.12 -22.20 -9.643 12.22 152.9 2.126 84.81 0.969 36 | 5.75 1.130 1.000 1.064 -22.14 -22.22 -9.593 12.29 171.6 2.126 89.84 0.969 37 | 5.80 1.130 1.000 1.064 -22.20 -22.28 -9.543 12.40 192.5 2.126 95.16 0.969 38 | 5.85 1.130 1.000 1.064 -22.33 -22.41 -9.493 12.58 216.0 2.126 100.8 0.969 39 | 5.90 1.130 1.000 1.064 -22.45 -22.53 -9.443 12.75 242.4 2.126 106.8 0.969 40 | 5.95 1.130 1.000 1.064 -22.51 -22.59 -9.393 12.86 272.0 2.126 113.1 0.969 41 | 6.00 1.130 1.000 1.064 -22.55 -22.63 -9.343 12.95 305.2 2.126 119.8 0.969 42 | 6.05 1.130 1.000 1.064 -22.58 -22.66 -9.293 13.03 342.4 2.126 126.9 0.969 43 | 6.10 1.131 1.000 1.064 -22.60 -22.68 -9.242 13.10 384.2 2.126 134.4 0.969 44 | 6.15 1.131 1.000 1.064 -22.59 -22.67 -9.192 13.14 431.1 2.126 142.4 0.969 45 | 6.20 1.131 1.000 1.064 -22.59 -22.67 -9.142 13.19 483.7 2.126 150.8 0.969 46 | 6.25 1.131 1.000 1.064 -22.61 -22.69 -9.092 13.26 542.8 2.126 159.8 0.969 47 | 6.30 1.131 1.000 1.064 -22.67 -22.75 -9.042 13.37 609.0 2.126 169.2 0.969 48 | 6.35 1.131 1.000 1.064 -22.74 -22.82 -8.992 13.49 683.3 2.126 179.3 0.969 49 | 6.40 1.131 1.000 1.064 -22.80 -22.88 -8.942 13.60 766.7 2.126 189.9 0.969 50 | 6.45 1.131 1.000 1.064 -22.84 -22.92 -8.892 13.69 860.3 2.126 201.2 0.969 51 | 6.50 1.131 1.000 1.064 -22.87 -22.95 -8.842 13.77 965.3 2.126 213.1 0.968 52 | 6.55 1.131 1.000 1.064 -22.89 -22.98 -8.792 13.84 1083.1 2.126 225.7 0.968 53 | 6.60 1.131 1.000 1.064 -22.91 -22.99 -8.742 13.91 1215.3 2.126 239.1 0.968 54 | 6.65 1.131 1.000 1.064 -22.92 -23.00 -8.692 13.97 1363.6 2.126 253.2 0.968 55 | 6.70 1.131 1.000 1.064 -22.93 -23.01 -8.642 14.03 1530.0 2.126 268.3 0.968 56 | 6.75 1.131 1.000 1.064 -22.94 -23.02 -8.592 14.09 1716.7 2.126 284.2 0.968 57 | 6.80 1.131 1.000 1.064 -22.94 -23.02 -8.542 14.14 1926.2 2.126 301.0 0.968 58 | 6.85 1.131 1.000 1.064 -22.94 -23.02 -8.492 14.19 2161.3 2.126 318.8 0.968 59 | 6.90 1.131 1.000 1.064 -22.93 -23.01 -8.442 14.23 2425.0 2.126 337.7 0.968 60 | 6.95 1.131 1.000 1.064 -22.92 -23.00 -8.392 14.27 2720.9 2.126 357.7 0.968 61 | 7.00 1.131 1.000 1.064 -22.91 -22.99 -8.342 14.31 3052.9 2.126 378.9 0.968 62 | 7.05 1.131 1.000 1.064 -22.90 -22.98 -8.292 14.35 3425.5 2.126 401.4 0.968 63 | 7.10 1.131 1.000 1.064 -22.90 -22.98 -8.242 14.40 3843.4 2.126 425.2 0.968 64 | 7.15 1.131 1.000 1.064 -22.90 -22.98 -8.192 14.45 4312.4 2.126 450.4 0.968 65 | 7.20 1.131 1.000 1.064 -22.89 -22.97 -8.142 14.49 4838.6 2.126 477.0 0.968 66 | 7.25 1.131 1.000 1.064 -22.88 -22.96 -8.092 14.53 5429.1 2.126 505.3 0.968 67 | 7.30 1.131 1.000 1.064 -22.87 -22.95 -8.042 14.57 6091.5 2.126 535.3 0.968 68 | 7.35 1.131 1.000 1.064 -22.85 -22.94 -7.992 14.60 6834.8 2.126 567.0 0.968 69 | 7.40 1.131 1.000 1.064 -22.84 -22.92 -7.942 14.64 7668.8 2.126 600.6 0.968 70 | 7.45 1.131 1.000 1.064 -22.82 -22.90 -7.892 14.67 8604.5 2.126 636.2 0.968 71 | 7.50 1.131 1.000 1.064 -22.81 -22.89 -7.842 14.71 9654.4 2.126 673.9 0.968 72 | 7.55 1.131 1.000 1.064 -22.79 -22.87 -7.792 14.74 10832.4 2.126 713.8 0.968 73 | 7.60 1.131 1.000 1.064 -22.77 -22.85 -7.742 14.77 12154.2 2.126 756.1 0.968 74 | 7.65 1.131 1.000 1.064 -22.75 -22.83 -7.692 14.80 13637.2 2.126 800.9 0.968 75 | 7.70 1.131 1.000 1.064 -22.73 -22.81 -7.642 14.83 15301.2 2.126 848.3 0.968 76 | 7.75 1.131 1.000 1.064 -22.71 -22.79 -7.592 14.86 17168.3 2.126 898.6 0.968 77 | 7.80 1.131 1.000 1.064 -22.69 -22.77 -7.542 14.89 19263.1 2.126 951.8 0.968 78 | 7.85 1.131 1.000 1.064 -22.67 -22.75 -7.492 14.92 21613.6 2.126 1008.2 0.968 79 | 7.90 1.131 1.000 1.064 -22.65 -22.73 -7.442 14.95 24250.9 2.126 1068.0 0.968 80 | 7.95 1.131 1.000 1.064 -22.62 -22.70 -7.392 14.97 27209.9 2.126 1131.3 0.968 81 | 8.00 1.131 1.000 1.064 -22.60 -22.68 -7.342 15.00 30530.1 2.126 1198.3 0.968 82 | 8.05 1.131 1.000 1.064 -22.58 -22.66 -7.292 15.03 34255.3 2.126 1269.3 0.968 83 | 8.10 1.131 1.000 1.064 -22.56 -22.64 -7.242 15.06 38435.1 2.126 1344.5 0.968 84 | 8.15 1.131 1.000 1.064 -22.54 -22.62 -7.192 15.09 43124.9 2.126 1424.2 0.968 85 | 8.20 1.131 1.000 1.064 -22.51 -22.60 -7.142 15.11 48387.0 2.126 1508.6 0.968 86 | 8.25 1.131 1.000 1.064 -22.49 -22.57 -7.092 15.14 54291.1 2.126 1598.0 0.968 87 | 8.30 1.131 1.000 1.064 -22.47 -22.55 -7.042 15.17 60915.6 2.126 1692.7 0.968 88 | 8.35 1.131 1.000 1.064 -22.45 -22.53 -6.992 15.20 68348.4 2.126 1792.9 0.968 89 | 8.40 1.131 1.000 1.064 -22.42 -22.51 -6.942 15.22 76688.2 2.126 1899.2 0.968 90 | 8.45 1.131 1.000 1.064 -22.40 -22.48 -6.892 15.25 86045.6 2.126 2011.7 0.968 91 | 8.50 1.131 1.000 1.064 -22.38 -22.46 -6.842 15.28 96544.8 2.126 2130.9 0.968 92 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_m-15.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0022 1.000 1.064 -26.00 -23.38 -11.66 11.69 1.483 2.118 8.368 1.986 2 | 4.05 0.0141 1.000 1.064 -24.66 -22.84 -11.60 11.20 1.682 2.118 8.913 1.964 3 | 4.10 0.0702 1.000 1.064 -23.52 -22.39 -11.53 10.81 1.986 2.118 9.683 1.867 4 | 4.15 0.2525 1.000 1.064 -22.62 -22.05 -11.41 10.52 2.586 2.118 11.05 1.609 5 | 4.20 0.5666 1.000 1.064 -22.11 -21.89 -11.27 10.41 3.594 2.118 13.03 1.299 6 | 4.25 0.8163 1.000 1.064 -21.97 -21.91 -11.16 10.47 4.650 2.118 14.82 1.127 7 | 4.30 0.9311 1.000 1.064 -22.01 -22.01 -11.08 10.62 5.535 2.118 16.16 1.062 8 | 4.35 0.9756 1.000 1.064 -22.11 -22.12 -11.02 10.79 6.349 2.118 17.31 1.039 9 | 4.40 0.9981 1.000 1.064 -22.20 -22.23 -10.97 10.94 7.203 2.119 18.44 1.027 10 | 4.45 1.021 1.000 1.064 -22.27 -22.30 -10.91 11.07 8.170 2.119 19.64 1.016 11 | 4.50 1.042 1.000 1.064 -22.31 -22.35 -10.86 11.17 9.263 2.119 20.91 1.006 12 | 4.55 1.055 1.000 1.064 -22.33 -22.38 -10.81 11.25 10.46 2.119 22.22 1.000 13 | 4.60 1.060 1.000 1.064 -22.34 -22.39 -10.76 11.31 11.76 2.119 23.56 0.997 14 | 4.65 1.063 1.000 1.064 -22.32 -22.37 -10.71 11.34 13.21 2.119 24.97 0.996 15 | 4.70 1.064 1.000 1.064 -22.26 -22.31 -10.66 11.33 14.83 2.119 26.46 0.996 16 | 4.75 1.066 1.000 1.064 -22.17 -22.23 -10.61 11.29 16.65 2.119 28.04 0.995 17 | 4.80 1.070 1.000 1.064 -22.06 -22.12 -10.55 11.23 18.73 2.119 29.73 0.992 18 | 4.85 1.082 1.000 1.064 -21.95 -22.01 -10.50 11.18 21.13 2.119 31.58 0.987 19 | 4.90 1.099 1.000 1.064 -21.88 -21.95 -10.45 11.16 23.89 2.119 33.58 0.979 20 | 4.95 1.113 1.000 1.064 -21.86 -21.94 -10.40 11.20 26.98 2.119 35.69 0.973 21 | 5.00 1.121 1.000 1.064 -21.88 -21.96 -10.34 11.27 30.39 2.119 37.87 0.970 22 | 5.05 1.125 1.000 1.064 -21.90 -21.98 -10.29 11.34 34.15 2.119 40.15 0.968 23 | 5.10 1.127 1.000 1.064 -21.91 -21.99 -10.24 11.41 38.35 2.119 42.55 0.967 24 | 5.15 1.128 1.000 1.064 -21.90 -21.98 -10.19 11.45 43.05 2.119 45.08 0.967 25 | 5.20 1.128 1.000 1.064 -21.88 -21.96 -10.14 11.48 48.31 2.119 47.75 0.967 26 | 5.25 1.128 1.000 1.064 -21.86 -21.94 -10.09 11.51 54.21 2.119 50.58 0.966 27 | 5.30 1.128 1.000 1.064 -21.85 -21.93 -10.04 11.55 60.83 2.119 53.58 0.966 28 | 5.35 1.128 1.000 1.064 -21.84 -21.92 -9.993 11.59 68.25 2.119 56.76 0.966 29 | 5.40 1.128 1.000 1.064 -21.87 -21.95 -9.943 11.67 76.58 2.119 60.12 0.966 30 | 5.45 1.128 1.000 1.064 -22.00 -22.08 -9.893 11.85 85.93 2.119 63.69 0.966 31 | 5.50 1.129 1.000 1.064 -22.21 -22.29 -9.843 12.11 96.42 2.119 67.46 0.966 32 | 5.55 1.129 1.000 1.064 -22.39 -22.47 -9.793 12.34 108.2 2.119 71.46 0.966 33 | 5.60 1.129 1.000 1.064 -22.49 -22.57 -9.743 12.49 121.4 2.119 75.69 0.966 34 | 5.65 1.129 1.000 1.064 -22.54 -22.62 -9.693 12.59 136.2 2.119 80.18 0.966 35 | 5.70 1.129 1.000 1.064 -22.55 -22.63 -9.643 12.65 152.8 2.119 84.93 0.966 36 | 5.75 1.129 1.000 1.064 -22.56 -22.64 -9.593 12.71 171.5 2.119 89.96 0.966 37 | 5.80 1.129 1.000 1.064 -22.62 -22.70 -9.543 12.82 192.4 2.119 95.29 0.966 38 | 5.85 1.129 1.000 1.064 -22.73 -22.81 -9.493 12.98 215.9 2.119 100.9 0.966 39 | 5.90 1.129 1.000 1.064 -22.82 -22.90 -9.443 13.12 242.2 2.119 106.9 0.966 40 | 5.95 1.129 1.000 1.064 -22.86 -22.94 -9.393 13.21 271.8 2.119 113.3 0.966 41 | 6.00 1.129 1.000 1.064 -22.89 -22.97 -9.343 13.29 304.9 2.119 120.0 0.966 42 | 6.05 1.129 1.000 1.064 -22.92 -23.00 -9.293 13.37 342.1 2.119 127.1 0.966 43 | 6.10 1.129 1.000 1.064 -22.93 -23.01 -9.243 13.43 383.9 2.119 134.6 0.966 44 | 6.15 1.129 1.000 1.064 -22.93 -23.00 -9.193 13.48 430.7 2.119 142.6 0.966 45 | 6.20 1.129 1.000 1.064 -22.92 -23.00 -9.143 13.52 483.3 2.119 151.0 0.966 46 | 6.25 1.129 1.000 1.064 -22.93 -23.01 -9.093 13.58 542.2 2.119 160.0 0.966 47 | 6.30 1.129 1.000 1.064 -22.97 -23.04 -9.043 13.67 608.4 2.119 169.5 0.966 48 | 6.35 1.129 1.000 1.064 -23.01 -23.09 -8.993 13.76 682.7 2.119 179.5 0.966 49 | 6.40 1.129 1.000 1.064 -23.04 -23.12 -8.943 13.84 766.0 2.119 190.1 0.966 50 | 6.45 1.129 1.000 1.064 -23.06 -23.14 -8.893 13.91 859.4 2.119 201.4 0.966 51 | 6.50 1.129 1.000 1.064 -23.07 -23.15 -8.843 13.97 964.3 2.119 213.3 0.966 52 | 6.55 1.129 1.000 1.064 -23.07 -23.15 -8.793 14.02 1082.0 2.119 226.0 0.966 53 | 6.60 1.129 1.000 1.064 -23.07 -23.15 -8.743 14.07 1214.0 2.119 239.4 0.966 54 | 6.65 1.129 1.000 1.064 -23.07 -23.15 -8.693 14.12 1362.2 2.119 253.6 0.966 55 | 6.70 1.129 1.000 1.064 -23.07 -23.15 -8.643 14.17 1528.4 2.119 268.6 0.966 56 | 6.75 1.129 1.000 1.064 -23.06 -23.14 -8.593 14.21 1714.8 2.119 284.5 0.966 57 | 6.80 1.129 1.000 1.064 -23.05 -23.13 -8.543 14.25 1924.1 2.119 301.4 0.966 58 | 6.85 1.129 1.000 1.064 -23.04 -23.12 -8.493 14.29 2158.9 2.119 319.2 0.966 59 | 6.90 1.129 1.000 1.064 -23.02 -23.10 -8.443 14.32 2422.3 2.119 338.1 0.966 60 | 6.95 1.129 1.000 1.064 -23.01 -23.09 -8.393 14.36 2717.9 2.119 358.2 0.966 61 | 7.00 1.129 1.000 1.064 -23.00 -23.08 -8.343 14.40 3049.5 2.119 379.4 0.966 62 | 7.05 1.129 1.000 1.064 -22.98 -23.06 -8.293 14.43 3421.6 2.119 401.9 0.966 63 | 7.10 1.129 1.000 1.064 -22.97 -23.05 -8.243 14.47 3839.1 2.119 425.7 0.966 64 | 7.15 1.129 1.000 1.064 -22.96 -23.04 -8.193 14.51 4307.6 2.119 450.9 0.966 65 | 7.20 1.129 1.000 1.064 -22.94 -23.02 -8.143 14.54 4833.2 2.119 477.6 0.966 66 | 7.25 1.129 1.000 1.064 -22.93 -23.00 -8.093 14.58 5422.9 2.119 505.9 0.966 67 | 7.30 1.129 1.000 1.064 -22.91 -22.99 -8.043 14.61 6084.6 2.119 535.9 0.966 68 | 7.35 1.129 1.000 1.064 -22.89 -22.97 -7.993 14.64 6827.1 2.119 567.7 0.966 69 | 7.40 1.129 1.000 1.064 -22.87 -22.95 -7.943 14.67 7660.1 2.119 601.3 0.966 70 | 7.45 1.129 1.000 1.064 -22.85 -22.93 -7.893 14.70 8594.8 2.119 636.9 0.966 71 | 7.50 1.129 1.000 1.064 -22.83 -22.91 -7.843 14.73 9643.5 2.119 674.7 0.966 72 | 7.55 1.129 1.000 1.064 -22.81 -22.89 -7.793 14.76 10820.2 2.119 714.6 0.966 73 | 7.60 1.129 1.000 1.064 -22.79 -22.87 -7.743 14.79 12140.4 2.119 757.0 0.966 74 | 7.65 1.129 1.000 1.064 -22.77 -22.85 -7.693 14.82 13621.8 2.119 801.8 0.966 75 | 7.70 1.129 1.000 1.064 -22.75 -22.83 -7.643 14.85 15283.9 2.119 849.4 0.966 76 | 7.75 1.129 1.000 1.064 -22.73 -22.81 -7.593 14.88 17148.8 2.119 899.7 0.966 77 | 7.80 1.129 1.000 1.064 -22.70 -22.78 -7.543 14.90 19241.3 2.119 953.0 0.966 78 | 7.85 1.129 1.000 1.064 -22.68 -22.76 -7.493 14.93 21589.1 2.119 1009.5 0.966 79 | 7.90 1.129 1.000 1.064 -22.66 -22.74 -7.443 14.96 24223.4 2.119 1069.3 0.966 80 | 7.95 1.129 1.000 1.064 -22.64 -22.72 -7.393 14.99 27179.1 2.119 1132.6 0.966 81 | 8.00 1.129 1.000 1.064 -22.62 -22.70 -7.343 15.02 30495.4 2.119 1199.7 0.966 82 | 8.05 1.129 1.000 1.064 -22.59 -22.67 -7.293 15.04 34216.4 2.119 1270.8 0.966 83 | 8.10 1.129 1.000 1.064 -22.57 -22.65 -7.243 15.07 38391.5 2.119 1346.1 0.966 84 | 8.15 1.129 1.000 1.064 -22.55 -22.63 -7.193 15.10 43075.9 2.119 1425.9 0.966 85 | 8.20 1.129 1.000 1.064 -22.53 -22.61 -7.143 15.13 48332.0 2.119 1510.4 0.966 86 | 8.25 1.129 1.000 1.064 -22.50 -22.58 -7.093 15.15 54229.4 2.119 1599.9 0.966 87 | 8.30 1.129 1.000 1.064 -22.48 -22.56 -7.043 15.18 60846.4 2.119 1694.7 0.966 88 | 8.35 1.129 1.000 1.064 -22.46 -22.54 -6.993 15.21 68270.8 2.119 1795.1 0.966 89 | 8.40 1.129 1.000 1.064 -22.44 -22.52 -6.943 15.24 76601.1 2.119 1901.5 0.966 90 | 8.45 1.129 1.000 1.064 -22.41 -22.49 -6.893 15.26 85947.8 2.119 2014.1 0.966 91 | 8.50 1.129 1.000 1.064 -22.39 -22.47 -6.843 15.29 96435.1 2.119 2133.5 0.966 92 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_m-20.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0022 1.000 1.064 -26.03 -23.40 -11.66 11.72 1.483 2.115 8.372 1.984 2 | 4.05 0.0141 1.000 1.064 -24.68 -22.86 -11.60 11.22 1.682 2.115 8.917 1.962 3 | 4.10 0.0700 1.000 1.064 -23.53 -22.40 -11.53 10.82 1.985 2.115 9.687 1.865 4 | 4.15 0.2528 1.000 1.064 -22.63 -22.05 -11.41 10.53 2.586 2.115 11.06 1.607 5 | 4.20 0.5668 1.000 1.064 -22.12 -21.90 -11.27 10.42 3.594 2.116 13.03 1.297 6 | 4.25 0.8163 1.000 1.064 -21.98 -21.92 -11.16 10.48 4.649 2.116 14.82 1.125 7 | 4.30 0.9310 1.000 1.064 -22.02 -22.02 -11.08 10.63 5.535 2.116 16.17 1.061 8 | 4.35 0.9755 1.000 1.064 -22.12 -22.14 -11.02 10.80 6.349 2.116 17.32 1.038 9 | 4.40 0.9980 1.000 1.064 -22.23 -22.25 -10.97 10.97 7.202 2.116 18.45 1.026 10 | 4.45 1.020 1.000 1.064 -22.31 -22.34 -10.91 11.11 8.169 2.116 19.65 1.015 11 | 4.50 1.042 1.000 1.064 -22.37 -22.42 -10.86 11.23 9.262 2.116 20.92 1.005 12 | 4.55 1.055 1.000 1.064 -22.44 -22.49 -10.81 11.36 10.45 2.116 22.23 0.999 13 | 4.60 1.060 1.000 1.064 -22.49 -22.54 -10.76 11.46 11.76 2.116 23.57 0.996 14 | 4.65 1.062 1.000 1.064 -22.51 -22.56 -10.71 11.53 13.21 2.116 24.98 0.995 15 | 4.70 1.064 1.000 1.064 -22.49 -22.54 -10.66 11.56 14.83 2.116 26.47 0.995 16 | 4.75 1.065 1.000 1.064 -22.40 -22.46 -10.61 11.52 16.65 2.116 28.05 0.994 17 | 4.80 1.070 1.000 1.064 -22.27 -22.32 -10.55 11.44 18.73 2.116 29.75 0.991 18 | 4.85 1.082 1.000 1.064 -22.13 -22.19 -10.50 11.36 21.12 2.116 31.59 0.986 19 | 4.90 1.099 1.000 1.064 -22.05 -22.12 -10.45 11.33 23.89 2.116 33.60 0.978 20 | 4.95 1.113 1.000 1.064 -22.05 -22.12 -10.40 11.39 26.98 2.116 35.70 0.972 21 | 5.00 1.121 1.000 1.064 -22.10 -22.17 -10.34 11.49 30.38 2.116 37.89 0.969 22 | 5.05 1.125 1.000 1.064 -22.16 -22.24 -10.29 11.60 34.15 2.116 40.17 0.967 23 | 5.10 1.127 1.000 1.064 -22.21 -22.28 -10.24 11.71 38.35 2.116 42.57 0.966 24 | 5.15 1.127 1.000 1.064 -22.23 -22.31 -10.19 11.78 43.04 2.116 45.10 0.966 25 | 5.20 1.128 1.000 1.064 -22.25 -22.33 -10.14 11.85 48.30 2.116 47.77 0.966 26 | 5.25 1.128 1.000 1.064 -22.26 -22.33 -10.09 11.91 54.20 2.116 50.61 0.965 27 | 5.30 1.128 1.000 1.064 -22.26 -22.34 -10.04 11.96 60.81 2.116 53.61 0.965 28 | 5.35 1.128 1.000 1.064 -22.26 -22.34 -9.993 12.01 68.24 2.116 56.78 0.965 29 | 5.40 1.128 1.000 1.064 -22.30 -22.38 -9.943 12.10 76.57 2.116 60.15 0.965 30 | 5.45 1.128 1.000 1.064 -22.42 -22.50 -9.893 12.27 85.91 2.116 63.71 0.965 31 | 5.50 1.128 1.000 1.064 -22.59 -22.67 -9.843 12.49 96.39 2.116 67.49 0.965 32 | 5.55 1.128 1.000 1.064 -22.74 -22.81 -9.793 12.69 108.2 2.116 71.49 0.965 33 | 5.60 1.128 1.000 1.064 -22.82 -22.90 -9.743 12.82 121.4 2.116 75.73 0.965 34 | 5.65 1.128 1.000 1.064 -22.86 -22.94 -9.693 12.91 136.2 2.116 80.21 0.965 35 | 5.70 1.128 1.000 1.064 -22.87 -22.95 -9.643 12.97 152.8 2.116 84.97 0.965 36 | 5.75 1.128 1.000 1.064 -22.89 -22.97 -9.593 13.04 171.4 2.116 90.00 0.965 37 | 5.80 1.128 1.000 1.064 -22.93 -23.01 -9.543 13.13 192.3 2.116 95.33 0.965 38 | 5.85 1.128 1.000 1.064 -23.00 -23.08 -9.493 13.25 215.8 2.116 101.0 0.965 39 | 5.90 1.128 1.000 1.064 -23.06 -23.14 -9.443 13.36 242.1 2.116 107.0 0.965 40 | 5.95 1.128 1.000 1.064 -23.09 -23.17 -9.393 13.44 271.7 2.116 113.3 0.965 41 | 6.00 1.128 1.000 1.064 -23.10 -23.18 -9.343 13.50 304.8 2.116 120.0 0.965 42 | 6.05 1.128 1.000 1.064 -23.12 -23.20 -9.293 13.57 342.0 2.116 127.1 0.965 43 | 6.10 1.128 1.000 1.064 -23.12 -23.20 -9.243 13.62 383.8 2.116 134.7 0.965 44 | 6.15 1.128 1.000 1.064 -23.12 -23.20 -9.193 13.67 430.6 2.116 142.6 0.965 45 | 6.20 1.128 1.000 1.064 -23.12 -23.20 -9.143 13.72 483.1 2.116 151.1 0.965 46 | 6.25 1.128 1.000 1.064 -23.12 -23.20 -9.093 13.77 542.1 2.116 160.0 0.965 47 | 6.30 1.128 1.000 1.064 -23.13 -23.21 -9.043 13.83 608.2 2.116 169.5 0.965 48 | 6.35 1.128 1.000 1.064 -23.15 -23.23 -8.993 13.90 682.4 2.116 179.6 0.965 49 | 6.40 1.128 1.000 1.064 -23.16 -23.24 -8.943 13.96 765.7 2.116 190.2 0.965 50 | 6.45 1.128 1.000 1.064 -23.16 -23.24 -8.893 14.01 859.2 2.116 201.5 0.965 51 | 6.50 1.128 1.000 1.064 -23.16 -23.24 -8.843 14.06 964.0 2.116 213.4 0.965 52 | 6.55 1.128 1.000 1.064 -23.15 -23.23 -8.793 14.10 1081.6 2.116 226.1 0.965 53 | 6.60 1.128 1.000 1.064 -23.14 -23.22 -8.743 14.14 1213.6 2.116 239.5 0.965 54 | 6.65 1.128 1.000 1.064 -23.13 -23.21 -8.693 14.18 1361.7 2.116 253.7 0.965 55 | 6.70 1.128 1.000 1.064 -23.12 -23.20 -8.643 14.22 1527.8 2.116 268.7 0.965 56 | 6.75 1.128 1.000 1.064 -23.11 -23.19 -8.593 14.26 1714.3 2.116 284.6 0.965 57 | 6.80 1.128 1.000 1.064 -23.09 -23.17 -8.543 14.29 1923.4 2.116 301.5 0.965 58 | 6.85 1.128 1.000 1.064 -23.08 -23.16 -8.493 14.33 2158.1 2.116 319.3 0.965 59 | 6.90 1.128 1.000 1.064 -23.06 -23.14 -8.443 14.36 2421.5 2.116 338.3 0.965 60 | 6.95 1.128 1.000 1.064 -23.05 -23.13 -8.393 14.40 2716.9 2.116 358.3 0.965 61 | 7.00 1.128 1.000 1.064 -23.03 -23.11 -8.343 14.43 3048.4 2.116 379.5 0.965 62 | 7.05 1.128 1.000 1.064 -23.01 -23.09 -8.293 14.46 3420.4 2.116 402.0 0.965 63 | 7.10 1.128 1.000 1.064 -23.00 -23.07 -8.243 14.50 3837.8 2.116 425.8 0.965 64 | 7.15 1.128 1.000 1.064 -22.98 -23.06 -8.193 14.53 4306.0 2.116 451.1 0.965 65 | 7.20 1.128 1.000 1.064 -22.96 -23.04 -8.143 14.56 4831.5 2.116 477.8 0.965 66 | 7.25 1.128 1.000 1.064 -22.94 -23.02 -8.093 14.59 5421.0 2.116 506.1 0.965 67 | 7.30 1.128 1.000 1.064 -22.92 -23.00 -8.043 14.62 6082.4 2.116 536.1 0.965 68 | 7.35 1.128 1.000 1.064 -22.90 -22.98 -7.993 14.65 6824.6 2.116 567.9 0.965 69 | 7.40 1.128 1.000 1.064 -22.88 -22.96 -7.943 14.68 7657.4 2.116 601.5 0.965 70 | 7.45 1.128 1.000 1.064 -22.86 -22.94 -7.893 14.71 8591.7 2.116 637.2 0.965 71 | 7.50 1.128 1.000 1.064 -22.84 -22.92 -7.843 14.74 9640.0 2.116 674.9 0.965 72 | 7.55 1.128 1.000 1.064 -22.82 -22.90 -7.793 14.77 10816.3 2.116 714.9 0.965 73 | 7.60 1.128 1.000 1.064 -22.80 -22.88 -7.743 14.80 12136.1 2.116 757.3 0.965 74 | 7.65 1.128 1.000 1.064 -22.78 -22.86 -7.693 14.83 13616.9 2.116 802.1 0.965 75 | 7.70 1.128 1.000 1.064 -22.75 -22.83 -7.643 14.85 15278.4 2.116 849.7 0.965 76 | 7.75 1.128 1.000 1.064 -22.73 -22.81 -7.593 14.88 17142.7 2.116 900.0 0.965 77 | 7.80 1.128 1.000 1.064 -22.71 -22.79 -7.543 14.91 19234.4 2.116 953.4 0.965 78 | 7.85 1.128 1.000 1.064 -22.69 -22.77 -7.493 14.94 21581.3 2.116 1009.8 0.965 79 | 7.90 1.128 1.000 1.064 -22.67 -22.75 -7.443 14.97 24214.7 2.116 1069.7 0.965 80 | 7.95 1.128 1.000 1.064 -22.64 -22.72 -7.393 14.99 27169.3 2.116 1133.1 0.965 81 | 8.00 1.128 1.000 1.064 -22.62 -22.70 -7.343 15.02 30484.5 2.116 1200.2 0.965 82 | 8.05 1.128 1.000 1.064 -22.60 -22.68 -7.293 15.05 34204.1 2.116 1271.3 0.965 83 | 8.10 1.128 1.000 1.064 -22.58 -22.66 -7.243 15.08 38377.7 2.116 1346.7 0.965 84 | 8.15 1.128 1.000 1.064 -22.55 -22.63 -7.193 15.10 43060.5 2.116 1426.4 0.965 85 | 8.20 1.128 1.000 1.064 -22.53 -22.61 -7.143 15.13 48314.6 2.116 1511.0 0.965 86 | 8.25 1.128 1.000 1.064 -22.51 -22.59 -7.093 15.16 54209.9 2.116 1600.5 0.965 87 | 8.30 1.128 1.000 1.064 -22.49 -22.56 -7.043 15.19 60824.5 2.116 1695.3 0.965 88 | 8.35 1.128 1.000 1.064 -22.46 -22.54 -6.993 15.21 68246.2 2.116 1795.8 0.965 89 | 8.40 1.128 1.000 1.064 -22.44 -22.52 -6.943 15.24 76573.5 2.116 1902.2 0.965 90 | 8.45 1.128 1.000 1.064 -22.42 -22.50 -6.893 15.27 85916.9 2.116 2014.9 0.965 91 | 8.50 1.128 1.000 1.064 -22.39 -22.47 -6.843 15.29 96400.4 2.116 2134.3 0.965 92 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_m-30.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0022 1.000 1.064 -26.04 -23.41 -11.66 11.73 1.479 2.114 8.365 1.987 2 | 4.05 0.0141 1.000 1.064 -24.69 -22.87 -11.60 11.23 1.682 2.114 8.919 1.961 3 | 4.10 0.0701 1.000 1.064 -23.53 -22.40 -11.53 10.82 1.985 2.114 9.690 1.864 4 | 4.15 0.2528 1.000 1.064 -22.63 -22.06 -11.41 10.53 2.586 2.114 11.06 1.606 5 | 4.20 0.5669 1.000 1.064 -22.12 -21.90 -11.27 10.42 3.594 2.115 13.04 1.297 6 | 4.25 0.8163 1.000 1.064 -21.98 -21.92 -11.16 10.48 4.649 2.115 14.83 1.125 7 | 4.30 0.9310 1.000 1.064 -22.03 -22.02 -11.08 10.64 5.535 2.115 16.18 1.060 8 | 4.35 0.9755 1.000 1.064 -22.13 -22.15 -11.02 10.81 6.349 2.115 17.32 1.037 9 | 4.40 0.9980 1.000 1.064 -22.24 -22.26 -10.97 10.98 7.202 2.115 18.45 1.026 10 | 4.45 1.020 1.000 1.064 -22.33 -22.36 -10.91 11.13 8.169 2.115 19.65 1.015 11 | 4.50 1.042 1.000 1.064 -22.40 -22.45 -10.86 11.26 9.261 2.115 20.92 1.004 12 | 4.55 1.055 1.000 1.064 -22.49 -22.54 -10.81 11.41 10.45 2.115 22.23 0.998 13 | 4.60 1.060 1.000 1.064 -22.57 -22.62 -10.76 11.54 11.76 2.115 23.58 0.996 14 | 4.65 1.062 1.000 1.064 -22.63 -22.68 -10.71 11.65 13.21 2.115 24.99 0.995 15 | 4.70 1.064 1.000 1.064 -22.63 -22.69 -10.66 11.70 14.83 2.115 26.48 0.994 16 | 4.75 1.065 1.000 1.064 -22.55 -22.61 -10.61 11.67 16.65 2.115 28.06 0.993 17 | 4.80 1.070 1.000 1.064 -22.39 -22.45 -10.55 11.56 18.73 2.115 29.75 0.991 18 | 4.85 1.082 1.000 1.064 -22.23 -22.29 -10.50 11.46 21.12 2.115 31.60 0.986 19 | 4.90 1.099 1.000 1.064 -22.15 -22.21 -10.45 11.43 23.89 2.115 33.60 0.978 20 | 4.95 1.113 1.000 1.064 -22.16 -22.23 -10.40 11.50 26.98 2.115 35.71 0.972 21 | 5.00 1.121 1.000 1.064 -22.24 -22.31 -10.34 11.63 30.38 2.115 37.90 0.968 22 | 5.05 1.125 1.000 1.064 -22.33 -22.41 -10.29 11.77 34.15 2.115 40.18 0.966 23 | 5.10 1.126 1.000 1.064 -22.43 -22.51 -10.24 11.92 38.34 2.115 42.58 0.966 24 | 5.15 1.127 1.000 1.064 -22.52 -22.60 -10.19 12.07 43.04 2.115 45.11 0.965 25 | 5.20 1.128 1.000 1.064 -22.60 -22.67 -10.14 12.20 48.30 2.115 47.78 0.965 26 | 5.25 1.128 1.000 1.064 -22.66 -22.74 -10.09 12.31 54.20 2.115 50.62 0.965 27 | 5.30 1.128 1.000 1.064 -22.72 -22.80 -10.04 12.42 60.81 2.115 53.62 0.965 28 | 5.35 1.128 1.000 1.064 -22.77 -22.85 -9.993 12.52 68.23 2.115 56.80 0.965 29 | 5.40 1.128 1.000 1.064 -22.82 -22.90 -9.943 12.62 76.56 2.115 60.16 0.965 30 | 5.45 1.128 1.000 1.064 -22.90 -22.98 -9.893 12.75 85.90 2.115 63.73 0.965 31 | 5.50 1.128 1.000 1.064 -22.98 -23.06 -9.843 12.88 96.38 2.115 67.50 0.965 32 | 5.55 1.128 1.000 1.064 -23.04 -23.12 -9.793 12.99 108.1 2.115 71.50 0.965 33 | 5.60 1.128 1.000 1.064 -23.08 -23.16 -9.743 13.08 121.3 2.115 75.74 0.965 34 | 5.65 1.128 1.000 1.064 -23.12 -23.20 -9.693 13.17 136.1 2.115 80.23 0.965 35 | 5.70 1.128 1.000 1.064 -23.14 -23.22 -9.643 13.24 152.8 2.115 84.98 0.965 36 | 5.75 1.128 1.000 1.064 -23.16 -23.24 -9.593 13.31 171.4 2.115 90.02 0.965 37 | 5.80 1.128 1.000 1.064 -23.18 -23.26 -9.543 13.38 192.3 2.115 95.35 0.965 38 | 5.85 1.128 1.000 1.064 -23.20 -23.28 -9.493 13.45 215.8 2.115 101.0 0.965 39 | 5.90 1.128 1.000 1.064 -23.22 -23.30 -9.443 13.52 242.1 2.115 107.0 0.965 40 | 5.95 1.128 1.000 1.064 -23.23 -23.31 -9.393 13.58 271.7 2.115 113.3 0.965 41 | 6.00 1.128 1.000 1.064 -23.23 -23.31 -9.343 13.63 304.8 2.115 120.0 0.965 42 | 6.05 1.128 1.000 1.064 -23.24 -23.32 -9.293 13.69 342.0 2.115 127.2 0.965 43 | 6.10 1.128 1.000 1.064 -23.24 -23.32 -9.243 13.74 383.7 2.115 134.7 0.965 44 | 6.15 1.128 1.000 1.064 -23.23 -23.31 -9.193 13.78 430.5 2.115 142.7 0.965 45 | 6.20 1.128 1.000 1.064 -23.23 -23.31 -9.143 13.83 483.1 2.115 151.1 0.965 46 | 6.25 1.128 1.000 1.064 -23.23 -23.31 -9.093 13.88 542.0 2.115 160.1 0.965 47 | 6.30 1.128 1.000 1.064 -23.22 -23.30 -9.043 13.92 608.2 2.115 169.6 0.965 48 | 6.35 1.128 1.000 1.064 -23.23 -23.30 -8.993 13.98 682.4 2.115 179.6 0.965 49 | 6.40 1.128 1.000 1.064 -23.22 -23.30 -8.943 14.02 765.6 2.115 190.2 0.965 50 | 6.45 1.128 1.000 1.064 -23.21 -23.29 -8.893 14.06 859.0 2.115 201.5 0.965 51 | 6.50 1.128 1.000 1.064 -23.20 -23.28 -8.843 14.10 963.9 2.115 213.5 0.965 52 | 6.55 1.128 1.000 1.064 -23.19 -23.26 -8.793 14.14 1081.5 2.115 226.1 0.965 53 | 6.60 1.128 1.000 1.064 -23.17 -23.25 -8.743 14.17 1213.4 2.115 239.5 0.965 54 | 6.65 1.128 1.000 1.064 -23.16 -23.24 -8.693 14.21 1361.5 2.115 253.7 0.965 55 | 6.70 1.128 1.000 1.064 -23.14 -23.22 -8.643 14.24 1527.6 2.115 268.7 0.965 56 | 6.75 1.128 1.000 1.064 -23.13 -23.21 -8.593 14.28 1714.0 2.115 284.7 0.965 57 | 6.80 1.128 1.000 1.064 -23.11 -23.19 -8.543 14.31 1923.2 2.115 301.5 0.965 58 | 6.85 1.128 1.000 1.064 -23.09 -23.17 -8.493 14.34 2157.8 2.115 319.4 0.965 59 | 6.90 1.128 1.000 1.064 -23.08 -23.16 -8.443 14.38 2421.1 2.115 338.3 0.965 60 | 6.95 1.128 1.000 1.064 -23.06 -23.14 -8.393 14.41 2716.5 2.115 358.4 0.965 61 | 7.00 1.128 1.000 1.064 -23.04 -23.12 -8.343 14.44 3048.0 2.115 379.6 0.965 62 | 7.05 1.128 1.000 1.064 -23.03 -23.10 -8.293 14.48 3419.9 2.115 402.1 0.965 63 | 7.10 1.128 1.000 1.064 -23.01 -23.09 -8.243 14.51 3837.2 2.115 425.9 0.965 64 | 7.15 1.128 1.000 1.064 -22.99 -23.07 -8.193 14.54 4305.4 2.115 451.2 0.965 65 | 7.20 1.128 1.000 1.064 -22.97 -23.05 -8.143 14.57 4830.7 2.115 477.9 0.965 66 | 7.25 1.128 1.000 1.064 -22.95 -23.03 -8.093 14.60 5420.2 2.115 506.2 0.965 67 | 7.30 1.128 1.000 1.064 -22.93 -23.01 -8.043 14.63 6081.5 2.115 536.2 0.965 68 | 7.35 1.128 1.000 1.064 -22.91 -22.99 -7.993 14.66 6823.6 2.115 568.0 0.965 69 | 7.40 1.128 1.000 1.064 -22.89 -22.96 -7.943 14.69 7656.2 2.115 601.6 0.965 70 | 7.45 1.128 1.000 1.064 -22.86 -22.94 -7.893 14.71 8590.4 2.115 637.3 0.965 71 | 7.50 1.128 1.000 1.064 -22.84 -22.92 -7.843 14.74 9638.6 2.115 675.0 0.965 72 | 7.55 1.128 1.000 1.064 -22.82 -22.90 -7.793 14.77 10814.7 2.115 715.0 0.965 73 | 7.60 1.128 1.000 1.064 -22.80 -22.88 -7.743 14.80 12134.3 2.115 757.4 0.965 74 | 7.65 1.128 1.000 1.064 -22.78 -22.86 -7.693 14.83 13614.9 2.115 802.3 0.965 75 | 7.70 1.128 1.000 1.064 -22.76 -22.84 -7.643 14.86 15276.1 2.115 849.8 0.965 76 | 7.75 1.128 1.000 1.064 -22.73 -22.81 -7.593 14.88 17140.1 2.115 900.2 0.965 77 | 7.80 1.128 1.000 1.064 -22.71 -22.79 -7.543 14.91 19231.5 2.115 953.5 0.965 78 | 7.85 1.128 1.000 1.064 -22.69 -22.77 -7.493 14.94 21578.1 2.115 1010.0 0.965 79 | 7.90 1.128 1.000 1.064 -22.67 -22.75 -7.443 14.97 24211.0 2.115 1069.8 0.965 80 | 7.95 1.128 1.000 1.064 -22.65 -22.73 -7.393 15.00 27165.2 2.115 1133.2 0.965 81 | 8.00 1.128 1.000 1.064 -22.62 -22.70 -7.343 15.02 30479.9 2.115 1200.4 0.965 82 | 8.05 1.128 1.000 1.064 -22.60 -22.68 -7.293 15.05 34199.0 2.115 1271.5 0.965 83 | 8.10 1.128 1.000 1.064 -22.58 -22.66 -7.243 15.08 38371.9 2.115 1346.9 0.965 84 | 8.15 1.128 1.000 1.064 -22.56 -22.63 -7.193 15.11 43054.0 2.115 1426.7 0.965 85 | 8.20 1.128 1.000 1.064 -22.53 -22.61 -7.143 15.13 48307.4 2.115 1511.2 0.965 86 | 8.25 1.128 1.000 1.064 -22.51 -22.59 -7.093 15.16 54201.8 2.115 1600.8 0.965 87 | 8.30 1.128 1.000 1.064 -22.49 -22.57 -7.043 15.19 60815.4 2.115 1695.6 0.965 88 | 8.35 1.128 1.000 1.064 -22.46 -22.54 -6.993 15.21 68236.0 2.115 1796.1 0.965 89 | 8.40 1.128 1.000 1.064 -22.44 -22.52 -6.943 15.24 76562.1 2.115 1902.5 0.965 90 | 8.45 1.128 1.000 1.064 -22.42 -22.50 -6.893 15.27 85904.0 2.115 2015.2 0.965 91 | 8.50 1.128 1.000 1.064 -22.39 -22.47 -6.843 15.29 96385.9 2.115 2134.6 0.965 92 | -------------------------------------------------------------------------------- /extra/CoolFunctions/stripped_mzero.cie: -------------------------------------------------------------------------------- 1 | 4.00 0.0022 1.000 1.064 -26.04 -23.41 -11.66 11.73 1.483 2.114 8.374 1.983 2 | 4.05 0.0141 1.000 1.064 -24.69 -22.87 -11.60 11.23 1.682 2.114 8.919 1.961 3 | 4.10 0.0701 1.000 1.064 -23.53 -22.40 -11.53 10.82 1.985 2.114 9.690 1.864 4 | 4.15 0.2528 1.000 1.064 -22.63 -22.06 -11.41 10.53 2.586 2.114 11.06 1.606 5 | 4.20 0.5669 1.000 1.064 -22.12 -21.90 -11.27 10.42 3.594 2.115 13.04 1.297 6 | 4.25 0.8163 1.000 1.064 -21.98 -21.92 -11.16 10.48 4.649 2.115 14.83 1.125 7 | 4.30 0.9310 1.000 1.064 -22.03 -22.02 -11.08 10.64 5.535 2.115 16.18 1.060 8 | 4.35 0.9755 1.000 1.064 -22.13 -22.15 -11.02 10.81 6.349 2.115 17.33 1.037 9 | 4.40 0.9980 1.000 1.064 -22.24 -22.26 -10.97 10.98 7.202 2.115 18.45 1.026 10 | 4.45 1.020 1.000 1.064 -22.33 -22.36 -10.91 11.13 8.169 2.115 19.65 1.015 11 | 4.50 1.042 1.000 1.064 -22.41 -22.45 -10.86 11.27 9.261 2.115 20.93 1.004 12 | 4.55 1.055 1.000 1.064 -22.49 -22.54 -10.81 11.41 10.45 2.115 22.23 0.998 13 | 4.60 1.060 1.000 1.064 -22.58 -22.63 -10.76 11.55 11.76 2.115 23.58 0.996 14 | 4.65 1.062 1.000 1.064 -22.64 -22.70 -10.71 11.66 13.21 2.115 24.99 0.995 15 | 4.70 1.064 1.000 1.064 -22.65 -22.71 -10.66 11.72 14.83 2.115 26.48 0.994 16 | 4.75 1.065 1.000 1.064 -22.57 -22.63 -10.61 11.69 16.65 2.115 28.06 0.993 17 | 4.80 1.070 1.000 1.064 -22.41 -22.47 -10.55 11.58 18.73 2.115 29.75 0.991 18 | 4.85 1.082 1.000 1.064 -22.24 -22.30 -10.50 11.47 21.12 2.115 31.60 0.986 19 | 4.90 1.099 1.000 1.064 -22.16 -22.23 -10.45 11.44 23.89 2.115 33.61 0.978 20 | 4.95 1.113 1.000 1.064 -22.17 -22.25 -10.40 11.51 26.98 2.115 35.71 0.972 21 | 5.00 1.121 1.000 1.064 -22.25 -22.33 -10.34 11.64 30.38 2.115 37.90 0.968 22 | 5.05 1.125 1.000 1.064 -22.36 -22.44 -10.29 11.80 34.15 2.115 40.18 0.966 23 | 5.10 1.126 1.000 1.064 -22.46 -22.54 -10.24 11.95 38.34 2.115 42.58 0.966 24 | 5.15 1.127 1.000 1.064 -22.56 -22.64 -10.19 12.11 43.04 2.115 45.11 0.965 25 | 5.20 1.128 1.000 1.064 -22.66 -22.74 -10.14 12.26 48.30 2.115 47.78 0.965 26 | 5.25 1.128 1.000 1.064 -22.74 -22.82 -10.09 12.39 54.19 2.115 50.62 0.965 27 | 5.30 1.128 1.000 1.064 -22.82 -22.90 -10.04 12.52 60.81 2.115 53.62 0.965 28 | 5.35 1.128 1.000 1.064 -22.89 -22.97 -9.993 12.64 68.23 2.115 56.80 0.965 29 | 5.40 1.128 1.000 1.064 -22.95 -23.03 -9.943 12.75 76.56 2.115 60.16 0.965 30 | 5.45 1.128 1.000 1.064 -23.01 -23.08 -9.893 12.86 85.90 2.115 63.73 0.965 31 | 5.50 1.128 1.000 1.064 -23.05 -23.13 -9.843 12.95 96.38 2.115 67.50 0.965 32 | 5.55 1.128 1.000 1.064 -23.09 -23.17 -9.793 13.04 108.1 2.115 71.50 0.965 33 | 5.60 1.128 1.000 1.064 -23.13 -23.21 -9.743 13.13 121.3 2.115 75.74 0.965 34 | 5.65 1.128 1.000 1.064 -23.16 -23.24 -9.693 13.21 136.1 2.115 80.23 0.965 35 | 5.70 1.128 1.000 1.064 -23.18 -23.26 -9.643 13.28 152.8 2.115 84.98 0.965 36 | 5.75 1.128 1.000 1.064 -23.20 -23.28 -9.593 13.35 171.4 2.115 90.02 0.965 37 | 5.80 1.128 1.000 1.064 -23.22 -23.30 -9.543 13.42 192.3 2.115 95.35 0.965 38 | 5.85 1.128 1.000 1.064 -23.23 -23.31 -9.493 13.48 215.8 2.115 101.0 0.965 39 | 5.90 1.128 1.000 1.064 -23.24 -23.32 -9.443 13.54 242.1 2.115 107.0 0.965 40 | 5.95 1.128 1.000 1.064 -23.25 -23.33 -9.393 13.60 271.6 2.115 113.3 0.965 41 | 6.00 1.128 1.000 1.064 -23.25 -23.33 -9.343 13.65 304.8 2.115 120.0 0.965 42 | 6.05 1.128 1.000 1.064 -23.25 -23.33 -9.293 13.70 342.0 2.115 127.2 0.965 43 | 6.10 1.128 1.000 1.064 -23.25 -23.33 -9.243 13.75 383.7 2.115 134.7 0.965 44 | 6.15 1.128 1.000 1.064 -23.25 -23.33 -9.193 13.80 430.5 2.115 142.7 0.965 45 | 6.20 1.128 1.000 1.064 -23.25 -23.32 -9.143 13.85 483.1 2.115 151.1 0.965 46 | 6.25 1.128 1.000 1.064 -23.24 -23.32 -9.093 13.89 542.0 2.115 160.1 0.965 47 | 6.30 1.128 1.000 1.064 -23.23 -23.31 -9.043 13.93 608.1 2.115 169.6 0.965 48 | 6.35 1.128 1.000 1.064 -23.23 -23.31 -8.993 13.98 682.3 2.115 179.6 0.965 49 | 6.40 1.128 1.000 1.064 -23.23 -23.30 -8.943 14.03 765.6 2.115 190.3 0.965 50 | 6.45 1.128 1.000 1.064 -23.21 -23.29 -8.893 14.06 859.0 2.115 201.5 0.965 51 | 6.50 1.128 1.000 1.064 -23.20 -23.28 -8.843 14.10 963.8 2.115 213.5 0.965 52 | 6.55 1.128 1.000 1.064 -23.19 -23.27 -8.793 14.14 1081.4 2.115 226.1 0.965 53 | 6.60 1.128 1.000 1.064 -23.18 -23.25 -8.743 14.18 1213.4 2.115 239.5 0.965 54 | 6.65 1.128 1.000 1.064 -23.16 -23.24 -8.693 14.21 1361.5 2.115 253.7 0.965 55 | 6.70 1.128 1.000 1.064 -23.15 -23.22 -8.643 14.25 1527.6 2.115 268.7 0.965 56 | 6.75 1.128 1.000 1.064 -23.13 -23.21 -8.593 14.28 1714.0 2.115 284.7 0.965 57 | 6.80 1.128 1.000 1.064 -23.11 -23.19 -8.543 14.31 1923.1 2.115 301.5 0.965 58 | 6.85 1.128 1.000 1.064 -23.10 -23.17 -8.493 14.35 2157.8 2.115 319.4 0.965 59 | 6.90 1.128 1.000 1.064 -23.08 -23.16 -8.443 14.38 2421.1 2.115 338.3 0.965 60 | 6.95 1.128 1.000 1.064 -23.06 -23.14 -8.393 14.41 2716.5 2.115 358.4 0.965 61 | 7.00 1.128 1.000 1.064 -23.05 -23.12 -8.343 14.45 3047.9 2.115 379.6 0.965 62 | 7.05 1.128 1.000 1.064 -23.03 -23.11 -8.293 14.48 3419.8 2.115 402.1 0.965 63 | 7.10 1.128 1.000 1.064 -23.01 -23.09 -8.243 14.51 3837.1 2.115 425.9 0.965 64 | 7.15 1.128 1.000 1.064 -22.99 -23.07 -8.193 14.54 4305.3 2.115 451.2 0.965 65 | 7.20 1.128 1.000 1.064 -22.97 -23.05 -8.143 14.57 4830.7 2.115 477.9 0.965 66 | 7.25 1.128 1.000 1.064 -22.95 -23.03 -8.093 14.60 5420.1 2.115 506.2 0.965 67 | 7.30 1.128 1.000 1.064 -22.93 -23.01 -8.043 14.63 6081.4 2.115 536.2 0.965 68 | 7.35 1.128 1.000 1.064 -22.91 -22.99 -7.993 14.66 6823.5 2.115 568.0 0.965 69 | 7.40 1.128 1.000 1.064 -22.89 -22.96 -7.943 14.69 7656.1 2.115 601.6 0.965 70 | 7.45 1.128 1.000 1.064 -22.86 -22.94 -7.893 14.71 8590.3 2.115 637.3 0.965 71 | 7.50 1.128 1.000 1.064 -22.84 -22.92 -7.843 14.74 9638.4 2.115 675.0 0.965 72 | 7.55 1.128 1.000 1.064 -22.82 -22.90 -7.793 14.77 10814.5 2.115 715.0 0.965 73 | 7.60 1.128 1.000 1.064 -22.80 -22.88 -7.743 14.80 12134.1 2.115 757.4 0.965 74 | 7.65 1.128 1.000 1.064 -22.78 -22.86 -7.693 14.83 13614.6 2.115 802.3 0.965 75 | 7.70 1.128 1.000 1.064 -22.76 -22.84 -7.643 14.86 15275.9 2.115 849.8 0.965 76 | 7.75 1.128 1.000 1.064 -22.74 -22.81 -7.593 14.89 17139.8 2.115 900.2 0.965 77 | 7.80 1.128 1.000 1.064 -22.71 -22.79 -7.543 14.91 19231.2 2.115 953.5 0.965 78 | 7.85 1.128 1.000 1.064 -22.69 -22.77 -7.493 14.94 21577.8 2.115 1010.0 0.965 79 | 7.90 1.128 1.000 1.064 -22.67 -22.75 -7.443 14.97 24210.6 2.115 1069.9 0.965 80 | 7.95 1.128 1.000 1.064 -22.65 -22.73 -7.393 15.00 27164.8 2.115 1133.3 0.965 81 | 8.00 1.128 1.000 1.064 -22.62 -22.70 -7.343 15.02 30479.4 2.115 1200.4 0.965 82 | 8.05 1.128 1.000 1.064 -22.60 -22.68 -7.293 15.05 34198.4 2.115 1271.5 0.965 83 | 8.10 1.128 1.000 1.064 -22.58 -22.66 -7.243 15.08 38371.3 2.115 1346.9 0.965 84 | 8.15 1.128 1.000 1.064 -22.56 -22.63 -7.193 15.11 43053.3 2.115 1426.7 0.965 85 | 8.20 1.128 1.000 1.064 -22.53 -22.61 -7.143 15.13 48306.6 2.115 1511.2 0.965 86 | 8.25 1.128 1.000 1.064 -22.51 -22.59 -7.093 15.16 54200.9 2.115 1600.8 0.965 87 | 8.30 1.128 1.000 1.064 -22.49 -22.57 -7.043 15.19 60814.4 2.115 1695.6 0.965 88 | 8.35 1.128 1.000 1.064 -22.46 -22.54 -6.993 15.21 68234.9 2.115 1796.1 0.965 89 | 8.40 1.128 1.000 1.064 -22.44 -22.52 -6.943 15.24 76560.8 2.115 1902.5 0.965 90 | 8.45 1.128 1.000 1.064 -22.42 -22.50 -6.893 15.27 85902.6 2.115 2015.3 0.965 91 | 8.50 1.128 1.000 1.064 -22.39 -22.47 -6.843 15.29 96384.3 2.115 2134.7 0.965 92 | --------------------------------------------------------------------------------