{"id":37064058,"url":"https://github.com/vosjo/nnaps","last_synced_at":"2026-01-14T07:29:13.548Z","repository":{"id":50151807,"uuid":"232091996","full_name":"vosjo/nnaps","owner":"vosjo","description":"Neural Network assisted Population Synthesis.","archived":false,"fork":false,"pushed_at":"2021-06-02T14:14:29.000Z","size":17012,"stargazers_count":7,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-18T19:43:28.582Z","etag":null,"topics":["astronomy","binary-evolution","machine-learning","population-synthesis","stellar-evolution"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vosjo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-01-06T12:01:41.000Z","updated_at":"2025-08-06T09:20:40.000Z","dependencies_parsed_at":"2022-09-26T20:20:32.144Z","dependency_job_id":null,"html_url":"https://github.com/vosjo/nnaps","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/vosjo/nnaps","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vosjo%2Fnnaps","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vosjo%2Fnnaps/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vosjo%2Fnnaps/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vosjo%2Fnnaps/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vosjo","download_url":"https://codeload.github.com/vosjo/nnaps/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vosjo%2Fnnaps/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28413228,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T05:26:33.345Z","status":"ssl_error","status_checked_at":"2026-01-14T05:21:57.251Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astronomy","binary-evolution","machine-learning","population-synthesis","stellar-evolution"],"created_at":"2026-01-14T07:29:12.840Z","updated_at":"2026-01-14T07:29:13.535Z","avatar_url":"https://github.com/vosjo.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nnaps)\n[![PyPI](https://img.shields.io/pypi/v/nnaps)](https://pypi.org/project/nnaps/)\n[![Documentation Status](https://readthedocs.org/projects/nnaps/badge/?version=latest)](https://nnaps.readthedocs.io/en/latest/?badge=latest)\n[![GitHub](https://img.shields.io/github/license/vosjo/nnaps)](https://github.com/vosjo/nnaps/blob/master/LICENSE)\n[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.3988965.svg)](https://doi.org/10.5281/zenodo.3988965)\n\n# Neural Network assisted Population Synthesis code\n\nNNaPS aims to be a simple and easy to use codebase for building a population synthesis code from a set of 1D \nstellar/binary evolution models. For example, with NNaPS, a set of MESA models can be turned into a population \nsynthesis code. \n\nNNaPS can extract interesting parameters from a grid of MESA models and even apply a CE ejection for binary models. \n\nBased on the extracted grid, NNaPS trains a neural network to act as an interpolator in the provided models, and can \nthen be used to predict new models, as long as their starting parameters are in the same range as those used to train \nthe network. \n\nLets look at an example:\n\n![wide sdB example](docs/wide_sdB_period_q_example.png)\n\nThe orbital period and mass ratio distribution of wide hot subdwarf binaries shows a very strong correlation. We want \nto study this correlation and predict the P-q distribution of wide sdB binaries in the galaxy. Using MESA, 2000 models \ncovering the observed parameter range were calculated (blue circles in the left figure). Using NNaPS, these models \nwere used to train a model and predict the P-q distribution of ~1\\,000\\,000 binaries (right figure). With this new\nBPS model we can now further explore the P-q distribution of different sub populations in our galaxy.\n\nIf you want to try out a BPS model that was created using NNaPS you can try MESA-bps. It allows you to predict the \norbital properties of a low mass (\u003c 2.0 Msol) binary after its interaction phase on the red giant branch.\n\nMESA-bps: https://mesa-bps.herokuapp.com/\n\n## Documentation\n\nThe detailed documentation is a work in progress, you can read the current version at\n[nnaps.readthedocs.io](https://nnaps.readthedocs.io/en/latest/)\n\n## Instalation instructions\n\nThe simplest way to install the latest stable release of NNaPS is using pip.\n\n    pip install nnaps\n\nTo uninstall NNaPS, run:\n\n    pip uninstall nnaps\n\n## Acknowledgements\n\nIf you use NNaPS in a publication, please cite:\n\n```tex\n@misc{nnaps,\n  author       = {{Vos}, Joris and {Bobrick}, Alexey and {Vu{\\v{c}}kovi{\\'c}}, Maja},\n  title        = {Neural Network assisted Population Synthesis},\n  month        = aug,\n  year         = 2020,\n  publisher    = {Zenodo},\n  version      = {0.0.1},\n  doi          = {10.5281/zenodo.3988965},\n  url          = {https://doi.org/10.5281/zenodo.3988965}\n}\n``` \n\n## Compress and Extract a grid of MESA models\n\n![nnaps-mesa workflow](docs/mesa_process_diagram.png)\n\nIf you have a calculate a grid of MESA models the first step is to compress the output and keep only what is of \ninterest in your study. This can decrease the necessary storage space by a factor of 10 or more, and will make dealing \nwith a large MESA grid on a laptop much more manageable. \n\nCompressing a grid of MESA runs to hdf5 format can be done with the nnaps-mesa command line tool:\n\n    nnaps-mesa -2h5 \u003cinput folder\u003e -o \u003coutput folder\u003e\n    \nOnce a MESA grid is compressed, all interesting parameters can be extracted from the models and stored in a 2D csv \ntable:\n\n    nnaps-mesa -extract \u003cinput folder\u003e -o \u003coutput csv filename\u003e\n\nThe produced csv file can be used to create a predictive model. See the documentation for details on the nnaps-mesa\ntool.\n\nIf you would be looking for a simple tool to inspect a large grid of MESA models and their extracted parameters from\nyour browser, have a look at: [Track Explorer](https://github.com/vosjo/trackExplorer)\n\n## Simple predictor\n\nNNaPS requires a setup file or setup dictionary telling it what to do. The minimaly necessary setup includes a list \nof features and targets together with the path to the training data. Using the test data sample, the simplest model \nsetup file in yaml format is the following:\n\n```yaml\ndatafile: '\u003cpath to data file\u003e'\nfeatures:\n   - ...\nregressors:\n   - ...\nclassifiers:\n   - ...\n```\n\n**datafile**: path to the file containing the training data.  This file is read with the pandas.read_csv() function, \nand should be structured in an appropriate way.  \n**features**: a list of the features to use when predicting a model. Think of these as the X parameter of your \nprediction function.  \n**regressors**: a list of the numerical targets for the model. These are the Y parameters of the prediction function. \nA regressor has to he a continuous numerical value. For a categorical numerical value use a classifier.  \n**classifiers**: a list of the categorical targets for the model. These are the Y parameters that are not numerical, \nor the not continuous. \n\nThe entire process of fitting the data and predicting the targets of new data can be as simple as:\n\n```python\nfrom nnaps import predictors\n    \npredictor = predictors.FCPredictor(setup_file='setup.yaml')\n    \npredictor.fit(epochs=100)\n\nnew_predictions = predictor.predict(new_data)\n```\n\nLet's go over all steps in a bit more detail:\n\n#### The data\n\nLets check the data. In this example we will use the test data provided in the test directory of the NNaPS package. \n```python\nimport pandas as pd\n\ndata = pd.read_csv('tests/BesanconGalactic_summary.txt')\n    \nprint(data.head())\n```    \n\n|    |   M1  |  Pinit     | qinit    | FeHinit   | Pfinal     | qfinal   | product | binary_type  |\n|----|-------|------------|----------|-----------|------------|----------|---------|--------------|\n|  0 | 0.744 | 134.470005 | 1.095729 | -0.912521 | 294.031588 | 0.608444 | He-WD   | single-lined |\n|  1 | 0.813 | 225.000014 | 2.524845 | -0.806781 | 153.634007 | 1.031585 | He-WD   | single-lined |\n|  2 | 0.876 | 111.550009 | 2.190000 | -0.918768 | 104.970587 | 0.912802 | He-WD   | single-lined |\n|  3 | 0.890 | 512.700045 | 2.386059 | -0.878982 | 394.729424 | 1.396449 | HB      | single-lined |\n|  4 | 0.893 | 102.630007 | 1.485857 | -0.731017 | 228.613065 | 0.640067 | He-WD   | double-lined |\n\nThe dataframe contains the features, which are all numerical continuous variables: M1, Pinit,qinit and FeHinit. \nAnd the 4 targets: Pfinal, qfinal, product and binary_type. The first two targets are also continuous numerical\nvariables and are thus regressors. The last two targets are categorical variables, and are thus classifiers.  \n\nBased on this knownledge, we can make te following setup file:\n\n```yaml\ndatafile: 'tests/BesanconGalactic_summary.txt'\nfeatures:\n   - M1\n   - qinit\n   - Pinit\n   - FeHinit\nregressors:\n   - Pfinal\n   - qfinal\nclassifiers:\n   - product\n   - binary_type\n```\n\n#### Setting up the model and training\n\nUsing the setup file a predictor can be constructed and fitted:\n\n```python\nfrom nnaps import predictors\n    \npredictor = predictors.FCPredictor(setup_file='test_setup.yaml')\n    \npredictor.fit(epochs=100)\n```    \n\n    Train on 1648 samples, validate on 412 samples\n    Epoch 1/100\n     - 2s - loss: 696880.9575 - Pfinal_loss: 695673.0000 - qfinal_loss: 0.2186 - product_loss: 1.8115 - binary_type_loss: 0.6274 - Pfinal_accuracy: 0.0000e+00 - Pfinal_mae: 607.1440 - qfinal_accuracy: 0.0000e+00 - qfinal_mae: 0.3886 - product_accuracy: 0.1475 - product_mae: 0.2783 - binary_type_accuracy: 0.7737 - binary_type_mae: 0.4420 - val_loss: 808298.6068 - val_Pfinal_loss: 767784.4375 - val_qfinal_loss: 0.1991 - val_product_loss: 1.8002 - val_binary_type_loss: 0.6387 - val_Pfinal_accuracy: 0.0000e+00 - val_Pfinal_mae: 603.3589 - val_qfinal_accuracy: 0.0000e+00 - val_qfinal_mae: 0.3821 - val_product_accuracy: 0.1723 - val_product_mae: 0.2781 - val_binary_type_accuracy: 0.7621 - val_binary_type_mae: 0.4410\n    Epoch 2/100\n     - 0s - loss: 696340.1365 - Pfinal_loss: 696977.0625 - qfinal_loss: 0.2867 - product_loss: 1.8291 - binary_type_loss: 0.5913 - Pfinal_accuracy: 0.0000e+00 - Pfinal_mae: 606.6785 - qfinal_accuracy: 0.0000e+00 - qfinal_mae: 0.4482 - product_accuracy: 0.1056 - product_mae: 0.2791 - binary_type_accuracy: 0.7779 - binary_type_mae: 0.4019 - val_loss: 807560.4800 - val_Pfinal_loss: 767050.8750 - val_qfinal_loss: 0.2407 - val_product_loss: 1.8078 - val_binary_type_loss: 0.6247 - val_Pfinal_accuracy: 0.0000e+00 - val_Pfinal_mae: 602.7472 - val_qfinal_accuracy: 0.0000e+00 - val_qfinal_mae: 0.4202 - val_product_accuracy: 0.0267 - val_product_mae: 0.2784 - val_binary_type_accuracy: 0.7621 - val_binary_type_mae: 0.3860\n     ...\n     Epoch 100/100\n     - 0s - loss: 97412.9127 - Pfinal_loss: 96999.7812 - qfinal_loss: 0.0905 - product_loss: 1.1475 - binary_type_loss: 0.4588 - Pfinal_accuracy: 0.0000e+00 - Pfinal_mae: 161.2016 - qfinal_accuracy: 0.0000e+00 - qfinal_mae: 0.2201 - product_accuracy: 0.6383 - product_mae: 0.1970 - binary_type_accuracy: 0.8149 - binary_type_mae: 0.3309 - val_loss: 223666.4350 - val_Pfinal_loss: 184591.3125 - val_qfinal_loss: 0.0667 - val_product_loss: 1.1004 - val_binary_type_loss: 0.4510 - val_Pfinal_accuracy: 0.0000e+00 - val_Pfinal_mae: 155.4490 - val_qfinal_accuracy: 0.0000e+00 - val_qfinal_mae: 0.2007 - val_product_accuracy: 0.6893 - val_product_mae: 0.2050 - val_binary_type_accuracy: 0.8350 - val_binary_type_mae: 0.3043\n\nThis creates the predictor using a the 'test_setup.yaml' file, and then trains it on the provided data. The number of \nepochs is the number of iterations to be used in the gradient descent learning. After learning you can check the report\nif the model is good enough, or if more iterations are necessary.\n\n#### Checking the learning progress\n\nAfter training the predictor, you can check how well it managed to fit the training data. Before it started fitting, \nthe predictor set part of the training data separate to test how well it's predictions are. This is the validation\nset. By checking how well the predictor works for this data, you can get an idea of the expected error on new data.\n\nYou can save the training report to html file as follows:\n\n```python\npredictor.make_training_history_report('report.html')\n\n``` \n\n#### Making predictions\n\nWhen you are satisfied that your model is good enough, you can make predictions on new data.\n\nPredicting new models is then as simple as providing a pandas DataFrame with the features (X parameters) of the new\nmodels you want to predict to the BPS_predictor. We can have the system predict the targets for the 100 - 110th\ntraining sample. \n\n```python  \nnew_predictions = predictor.predict(data=data.iloc[100:110])\n\nprint(new_predictions)\n```\n\n|   | Pfinal     | qfinal   | product | binary_type  |\n|---|------------|----------|---------|--------------|\n| 0 | 1448.75939 | 0.613978 | HB      | single-lined |\n| 1 | 771.150024 | 0.432204 | He-WD   | single-lined |\n| 2 | 254.810944 | 0.295612 | He-WD   | single-lined |\n| 3 | 455.564545 | 0.348135 | He-WD   | single-lined |\n| 4 | 583.579712 | 0.381909 | He-WD   | single-lined |\n| 5 | 150.147385 | 0.267372 | He-WD   | single-lined |\n| 6 | 565.826782 | 0.378209 | He-WD   | single-lined |\n| 7 | 1213.60022 | 0.551243 | HB      | single-lined |\n| 8 | 2370.94384 | 0.859896 | HB      | single-lined |\n| 9 | 337.348907 | 0.316895 | He-WD   | single-lined |    \n\nnew_predictions is a pandas dataframe with the predictions and features of the provided.\n\nThe trained model can be saved to hdf5 format and loaded again for later use:\n\n```python  \npredictor.save_model('model.h5')\n```\n\nLoading a saved models can be done in two ways:\n\n```python\n# load into an existing predictor object\npredictor.load_model('model.h5')\n\n# or create a new predictor object from the saved model\npredictors.BPS_predictor(saved_model='model.h5')\n``` \n\n\n## Advanced predictor\n\nIt is possible to define many more setting in the setup file. A complete setupfile would look like:\n\n```yaml\ndatafile: 'tests/BesanconGalactic_summary.txt'\n\nfeatures:\n   M1:\n      processor: StandardScaler\n   qinit:\n      processor: StandardScaler\n   Pinit:\n      processor: StandardScaler\n   FeHinit:\n      processor: StandardScaler\nregressors:\n   Pfinal:\n      processor: None\n      loss: mean_absolute_percentage_error\n   qfinal:\n      processor: None\n      loss: mean_squared_error\nclassifiers:\n   product: \n      processor: OneHotEncoder\n      loss: categorical_crossentropy\n   binary_type:\n      processor: OneHotEncoder\n      loss: categorical_crossentropy\n\nrandom_state: 42\ntrain_test_split: 0.2\n\nmodel:\n   - {'layer':'Dense',   'args':[100], 'kwargs': {'activation':'relu', 'name':'FC_1'} }\n   - {'layer':'Dropout', 'args':[0.1], 'kwargs': {'name':'DO_1'} }\n   - {'layer':'Dense',   'args':[75],  'kwargs': {'activation':'relu', 'name':'FC_2'} }\n   - {'layer':'Dropout', 'args':[0.1], 'kwargs': {'name':'DO_2'} }\n   - {'layer':'Dense',   'args':[50],  'kwargs': {'activation':'relu', 'name':'FC_3'} }\n   - {'layer':'Dropout', 'args':[0.1], 'kwargs': {'name':'DO_3'} }\n\noptimizer: 'adam'\noptimizer_kwargs: {'learning_rate':0.001, 'beta_1':0.9, 'beta_2':0.999}\nbatch_size: 128\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvosjo%2Fnnaps","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvosjo%2Fnnaps","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvosjo%2Fnnaps/lists"}