diff --git a/.github/workflows/CI_pyFrame3DD.yml b/.github/workflows/CI_pyFrame3DD.yml index 1fbc5fb..7b3e12d 100644 --- a/.github/workflows/CI_pyFrame3DD.yml +++ b/.github/workflows/CI_pyFrame3DD.yml @@ -5,85 +5,109 @@ on: [push, pull_request] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: - build_conda: - name: Build (${{ matrix.os }} Python ${{ matrix.python-version }}) + build_pip: + name: Pip Build (${{ matrix.os }}) - ${{ matrix.python-version }} runs-on: ${{ matrix.os }} - defaults: run: shell: bash -l {0} strategy: - fail-fast: False + fail-fast: false #true matrix: - os: ["ubuntu-latest", "windows-latest"] - python-version: ["3.8", "3.9", "3.10"] + os: ["ubuntu-latest", "macOS-latest", "windows-latest"] + python-version: ["3.9", "3.10", "3.11"] steps: + - name: Setup C/C++ Compiler + id: install_cc + uses: rlalik/setup-cpp-compiler@v1.2 + with: + compiler: gcc #clang + - name: checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + id: cp + with: + python-version: ${{ matrix.python-version }} + update-environment: true - # Official way to do miniconda, but it messes with the worker environment and shell - - name: Install miniconda - uses: conda-incubator/setup-miniconda@v2 + - name: Pip Install pyFrame3DD + env: + MESON_ARGS: -Dpython_target=${{ steps.cp.outputs.python-path }} + CC: '${{ steps.install_cc.outputs.cc }}' + CXX: '${{ steps.install_cc.outputs.cxx }}' + run: | + '${{ steps.cp.outputs.python-path }}' -m pip install -vv .[test] + + - name: Test run + run: | + '${{ steps.cp.outputs.python-path }}' -m pytest test + + + build_conda: + name: Conda Build (${{ matrix.os }}) - ${{ matrix.python-version }} + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash -el {0} + + strategy: + fail-fast: false #true + matrix: + os: ["ubuntu-latest", "macOS-latest", "windows-latest"] + python-version: ["3.9", "3.10", "3.11"] + + steps: + - name: checkout repository + uses: actions/checkout@v3 + + - uses: conda-incubator/setup-miniconda@v2 # https://github.com/marketplace/actions/setup-miniconda with: - miniconda-version: "latest" - channels: conda-forge + #mamba-version: "*" + miniforge-version: "latest" auto-update-conda: true python-version: ${{ matrix.python-version }} environment-file: environment.yml activate-environment: test auto-activate-base: false - # This is a less official, but more lightweight way to do miniconda - #- name: Install miniconda - # uses: s-weigand/setup-conda@v1 - # # https://github.com/marketplace/actions/setup-conda - # with: - # update-conda: true - # python-version: ${{ matrix.python-version }} - # conda-channels: conda-forge - # activate-conda: true - # - #- name: Update environment - # run: | - # conda env update --file environment.yml + # Install dependencies of WISDEM specific to windows + - name: Add dependencies windows specific + if: contains( matrix.os, 'windows') + run: | + conda install -y m2w64-toolchain libpython - # Install compilers - - name: Add compilers + # Install dependencies of WISDEM specific to windows + - name: Add dependencies mac specific + if: false == contains( matrix.os, 'windows') run: | - conda install compilers + conda install -y compilers - # Install dependencies of WISDEM specific to linux/mac - #- name: Add dependencies linux specific - # if: false == contains( matrix.os, 'windows') - # run: | - # conda install ninja - # conda init bash + # Install + - name: Debug + run: | + conda list + printenv - # Install dependencies of WISDEM specific to windows - #- name: Add dependencies windows specific + #- name: Setup tmate session + # uses: mxschmitt/action-tmate@v3 + # with: + # detached: true # if: contains( matrix.os, 'windows') - # run: | - # conda install -y m2w64-toolchain libpython - + # Install - name: Conda Install pyFrame3DD + env: + MESON_ARGS: "" run: | - python setup.py develop - - # Peek - #- name: Library name - # run: | - # ls - # echo "BREAK" - # ls pyframe3dd - # echo "BREAK" - # ls meson_build/pyframe3dd + python -m pip install . - # Run tests - - name: Conda Run pytest + - name: Test run run: | - pytest test + python -m pytest test diff --git a/.github/workflows/Publish_pyFrame3DD.yml b/.github/workflows/Publish_pyFrame3DD.yml new file mode 100644 index 0000000..c02e8d0 --- /dev/null +++ b/.github/workflows/Publish_pyFrame3DD.yml @@ -0,0 +1,71 @@ +name: Build and upload to PyPI + +# Build on every branch push, tag push, and pull request change: +#on: [push, pull_request] +# Alternatively, to publish when a (published) GitHub Release is created, use the following: +on: + release: + types: + - published + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - name: Setup C/C++ Compiler + id: install_cc + uses: rlalik/setup-cpp-compiler@v1.2 + with: + compiler: gcc #clang + + - name: Checkout + uses: actions/checkout@v4 + + - name: Build wheels + env: + CC: '${{ steps.install_cc.outputs.cc }}' + CXX: '${{ steps.install_cc.outputs.cxx }}' + uses: pypa/cibuildwheel@v2.16.1 + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Build sdist + run: pipx run build --sdist + + - uses: actions/upload-artifact@v3 + with: + path: dist/*.tar.gz + + upload_pypi: + needs: [build_wheels, build_sdist] + runs-on: ubuntu-latest + # upload to PyPI on every tag starting with 'v' + #if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + # alternatively, to publish when a GitHub Release is created, use the following rule: + if: github.event_name == 'release' && github.event.action == 'published' + steps: + - uses: actions/download-artifact@v3 + with: + # unpacks default artifact into dist/ + # if `name: artifact` is omitted, the action will create extra parent dir + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@v1.8.10 + with: + user: __token__ + password: ${{ secrets.pypi_password }} + # To test: repository_url: https://test.pypi.org/legacy/ diff --git a/.gitignore b/.gitignore index 5e13028..2e63d08 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ nosetests.xml .mr.developer.cfg .project .pydevproject + +# Emacs +*~ diff --git a/README.md b/README.md index 8051cd7..a1bd6fe 100644 --- a/README.md +++ b/README.md @@ -14,22 +14,22 @@ There is example code that shows usage contained in ``examples/exB.py``. This f ## Prerequisites -pyMAP requires a C compiler +pyFrame3DD requires a C compiler ## Install For detailed installation instructions of WISDEM modules see or to install pyFrame3DD by itself do: - $ python setup.py install + $ pip install WISDEM-pyFrame3DD ## Unit Tests - $ python test/test_frame.py + $ pytest test For software issues please use . For functionality and theory related questions and comments please use the NWTC forum for [Systems Engineering Software Questions](https://wind.nrel.gov/forum/wind/viewtopic.php?f=34&t=1002). ## License -Frame3DD uses the GNU GPL so this code must also be under the same license. +Frame3DD uses the GNU GPL so this code must also be under the same license. The larger WISDEM code has a special dispensation to use the Apache License. diff --git a/environment.yml b/environment.yml index 40e8cf7..7274e6b 100644 --- a/environment.yml +++ b/environment.yml @@ -1,5 +1,3 @@ -name: test - channels: - conda-forge - defaults diff --git a/meson.build b/meson.build index 4c80225..322e666 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,5 @@ project('pyframe3dd', 'c', - version : '1.2', - meson_version: '>= 0.60', + meson_version: '>= 1.1', default_options: [ 'buildtype=debugoptimized', ], @@ -16,6 +15,11 @@ if m_dep.found() add_project_link_arguments('-lm', language : 'c') endif +is_windows = host_machine.system() == 'windows' +add_project_arguments('-DANSI=1', language : 'c') +if is_windows + add_project_arguments('-D_WIN64=1', language : 'c') +endif # https://mesonbuild.com/Python-module.html # Here we differentiate from the python used by meson, py3_command, and that python target, py3_target. This is useful diff --git a/pyframe3dd/src/HPGmatrix.c b/pyframe3dd/src/HPGmatrix.c index c22fb39..dfbe867 100644 --- a/pyframe3dd/src/HPGmatrix.c +++ b/pyframe3dd/src/HPGmatrix.c @@ -299,11 +299,10 @@ void ldl_mprove( ){ double sdp; /* accumulate the r.h.s. in double precision */ double *resid, /* the residual error */ - rms_resid_new=0, /* the RMS error of the mprvd solution */ - *dvector(); /* allocate memory for a vector of doubles */ + rms_resid_new=0; /* the RMS error of the mprvd solution */ + //*dvector(); /* allocate memory for a vector of doubles */ int j,i, pd; - void ldl_dcmp(), - free_dvector(); + //void ldl_dcmp(), free_dvector(); resid = dvector(1,n); @@ -492,11 +491,10 @@ void ldl_mprove_pm ( double sdp; // accumulate the r.h.s. in double precision double *dx, // the residual error *dc, // update to partial r.h.s. vector, c - rms_resid_new=0.0, // the RMS error of the mprvd solution - *dvector(); // allocate memory for a vector of doubles + rms_resid_new=0.0; // the RMS error of the mprvd solution + //*dvector(); // allocate memory for a vector of doubles int j,i, pd; - void ldl_dcmp(), - free_dvector(); + //void ldl_dcmp(), free_dvector(); dx = dvector(1,n); dc = dvector(1,n); @@ -581,10 +579,10 @@ void PSB_update ( void pseudo_inv( double **A, double **Ai, int n, int m, double beta, int verbose ){ - double *diag, *b, *x, **AtA, **AtAi, tmp, tr_AtA=0.0, - *dvector(), **dmatrix(), error; + double *diag, *b, *x, **AtA, **AtAi, tmp, tr_AtA=0.0, error; + //*dvector(), **dmatrix(), error; int i,j,k, ok; - void ldl_dcmp(), ldl_mprove(), free_dvector(), free_dmatrix(); + //void ldl_dcmp(), ldl_mprove(), free_dvector(), free_dmatrix(); diag = dvector(1,n); b = dvector(1,n); diff --git a/pyframe3dd/src/NRutil.c b/pyframe3dd/src/NRutil.c index 04445fe..98e00d0 100644 --- a/pyframe3dd/src/NRutil.c +++ b/pyframe3dd/src/NRutil.c @@ -33,6 +33,7 @@ float *vector(long nl, long nh) v=(float *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(float))); if (!v) NRerror("allocation failure in vector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0.0; return v-nl+NR_END; } @@ -43,6 +44,7 @@ int *ivector(long nl, long nh) v=(int *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(int))); if (!v) NRerror("allocation failure in ivector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0; return v-nl+NR_END; } @@ -63,6 +65,7 @@ unsigned long *lvector(long nl, long nh) v=(unsigned long *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(long))); if (!v) NRerror("allocation failure in lvector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0; return v-nl+NR_END; } @@ -73,6 +76,7 @@ double *dvector(long nl, long nh) v=(double *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(double))); if (!v) NRerror("allocation failure in dvector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0.0; return v-nl+NR_END; } @@ -95,6 +99,9 @@ float **matrix(long nrl, long nrh, long ncl, long nch) m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + for (i=nrl; i<=nrh; i++) + for (long j=ncl; j<=nch; j++) + m[i][j]=0.0; /* return pointer to array of pointers to rows */ return m; @@ -119,6 +126,9 @@ double **dmatrix(long nrl, long nrh, long ncl, long nch) m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + for (i=nrl; i<=nrh; i++) + for (long j=ncl; j<=nch; j++) + m[i][j]=0.0; /* return pointer to array of pointers to rows */ return m; @@ -144,6 +154,9 @@ int **imatrix(long nrl, long nrh, long ncl, long nch) m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + for (i=nrl; i<=nrh; i++) + for (long j=ncl; j<=nch; j++) + m[i][j]=0; /* return pointer to array of pointers to rows */ return m; @@ -222,6 +235,11 @@ float ***f3tensor(long nrl, long nrh, long ncl, long nch, long ndl, long ndh) for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep; } + for (i=nrl; i<=nrh; i++) + for (j=ncl; j<=nch; j++) + for (long k=ndl; k<=ndh; k++) + t[i][j][k]=0.0; + /* return pointer to array of pointers to rows */ return t; } @@ -346,6 +364,12 @@ float ***D3matrix(int nrl, int nrh, int ncl, int nch, int nzl, int nzh) m[i][j] -= nzl; } } + + for (i=nrl; i<=nrh; i++) + for (j=ncl; j<=nch; j++) + for (int k=nzl; k<=nzh; k++) + m[i][j][k]=0.0; + return m; } @@ -369,6 +393,12 @@ double ***D3dmatrix(int nrl, int nrh, int ncl, int nch, int nzl, int nzh) m[i][j] -= nzl; } } + + for (i=nrl; i<=nrh; i++) + for (j=ncl; j<=nch; j++) + for (int k=nzl; k<=nzh; k++) + m[i][j][k]=0.0; + return m; } @@ -423,7 +453,7 @@ void NRerror(error_text) char error_text[]; /* Numerical Recipes standard error handler */ { - void exit(); + //void exit(); fprintf(stderr,"Numerical Recipes run-time error...\n"); fprintf(stderr,"%s\n",error_text); @@ -439,6 +469,7 @@ long nh,nl; v=(float *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(float))); if (!v) NRerror("allocation failure in vector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0.0; return v-nl+NR_END; } @@ -450,6 +481,7 @@ long nh,nl; v=(int *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(int))); if (!v) NRerror("allocation failure in ivector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0; return v-nl+NR_END; } @@ -472,6 +504,7 @@ long nh,nl; v=(unsigned long *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(long))); if (!v) NRerror("allocation failure in lvector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0; return v-nl+NR_END; } @@ -483,6 +516,7 @@ long nh,nl; v=(double *)malloc((unsigned int) ((nh-nl+1+NR_END)*sizeof(double))); if (!v) NRerror("allocation failure in dvector()"); + for (int k=0; k<(nh-nl+1+NR_END); k++) v[k]=0.0; return v-nl+NR_END; } @@ -506,6 +540,9 @@ long nch,ncl,nrh,nrl; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + for (i=nrl; i<=nrh; i++) + for (long j=ncl; j<=nch; j++) + m[i][j]=0.0; /* return pointer to array of pointers to rows */ return m; @@ -531,6 +568,9 @@ long nch,ncl,nrh,nrl; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + for (i=nrl; i<=nrh; i++) + for (long j=ncl; j<=nch; j++) + m[i][j]=0.0; /* return pointer to array of pointers to rows */ return m; @@ -557,6 +597,9 @@ long nch,ncl,nrh,nrl; m[nrl] -= ncl; for(i=nrl+1;i<=nrh;i++) m[i]=m[i-1]+ncol; + for (i=nrl; i<=nrh; i++) + for (long j=ncl; j<=nch; j++) + m[i][j]=0; /* return pointer to array of pointers to rows */ return m; @@ -639,6 +682,11 @@ long nch,ncl,ndh,ndl,nrh,nrl; for(j=ncl+1;j<=nch;j++) t[i][j]=t[i][j-1]+ndep; } + for (i=nrl; i<=nrh; i++) + for (j=ncl; j<=nch; j++) + for (long k=ndl; k<=ndh; k++) + t[i][j][k]=0.0; + /* return pointer to array of pointers to rows */ return t; } @@ -829,7 +877,7 @@ void save_vector( char filename[], float *V, int nl, int nh, const char *mode ) { FILE *fp_v; int i; - void exit(); + //void exit(); time_t now; if ((fp_v = fopen (filename, mode)) == NULL) { @@ -857,7 +905,7 @@ void save_dvector( char filename[], double *V, int nl, int nh, const char *mode { FILE *fp_v; int i; - void exit(); + //void exit(); time_t now; if ((fp_v = fopen (filename, mode)) == NULL) { @@ -885,7 +933,7 @@ void save_ivector( char filename[], int *V, int nl, int nh, const char *mode ) { FILE *fp_v; int i; - void exit(); + //void exit(); time_t now; if ((fp_v = fopen (filename, mode)) == NULL) { @@ -913,7 +961,7 @@ void save_matrix ( char filename[], float **A, int ml, int mh, int nl, int nh, i { FILE *fp_m; int i,j, rows, cols; - void exit(); + //void exit(); time_t now; if ( transpose ) rows = nh-nl+1; else rows = mh-ml+1; @@ -956,7 +1004,7 @@ void save_dmatrix ( char filename[], double **A, int ml, int mh, int nl, int nh, { FILE *fp_m; int i,j, rows, cols; - void exit(); + //void exit(); time_t now; if ( transpose ) rows = nh-nl+1; else rows = mh-ml+1; @@ -1001,7 +1049,7 @@ void save_ut_matrix ( char filename[], float **A, int n, const char *mode ) { FILE *fp_m; int i,j; - void exit(); + //void exit(); time_t now; if ((fp_m = fopen (filename, mode)) == NULL) { @@ -1038,7 +1086,7 @@ void save_ut_dmatrix ( char filename[], double **A, int n, const char *mode ) { FILE *fp_m; int i,j; - void exit(); + //void exit(); time_t now; if ((fp_m = fopen (filename, mode)) == NULL) { diff --git a/pyframe3dd/src/coordtrans.c b/pyframe3dd/src/coordtrans.c index b6eb54b..e89ad7c 100644 --- a/pyframe3dd/src/coordtrans.c +++ b/pyframe3dd/src/coordtrans.c @@ -134,7 +134,7 @@ void atma( double t7, double t8, double t9, double **m, float r1, float r2 ){ - double **a, **ma, **dmatrix(); + double **a, **ma;//, **dmatrix(); int i,j,k; a = dmatrix(1,12,1,12); diff --git a/pyframe3dd/src/frame3dd.c b/pyframe3dd/src/frame3dd.c index cd644a6..24ac3e8 100644 --- a/pyframe3dd/src/frame3dd.c +++ b/pyframe3dd/src/frame3dd.c @@ -683,10 +683,10 @@ void assemble_M( float *NMs, float *NMx, float *NMy, float *NMz, int lump, int debug ){ - double **m, /* element mass matrix in global coord */ - **dmatrix(); + double **m; /* element mass matrix in global coord */ + // **dmatrix(); int **ind, /* member-structure DoF index table */ - **imatrix(), + //**imatrix(), res=0, i, j, ii, jj, l, ll; char mass_fn[FILENMAX]; @@ -1094,7 +1094,7 @@ void deallocate( double **pkDx, double **pkDy, double **pkDz, double **pkRx, double **pkSy, double **pkSz ){ - void free(); + //void free(); free(xyz); diff --git a/pyframe3dd/src/frame3dd_io.c b/pyframe3dd/src/frame3dd_io.c index 6625209..fdd4f7b 100644 --- a/pyframe3dd/src/frame3dd_io.c +++ b/pyframe3dd/src/frame3dd_io.c @@ -624,7 +624,7 @@ int lim /* platform-dependent path sperator character ... */ -#if defined(WIN32) || defined(DJGPP) +#if defined(_WIN32) || defined(_WIN64) || defined(DJGPP) static const char sep = '\\'; #else static const char sep = '/'; @@ -636,7 +636,7 @@ static const char sep = '/'; * John Pye, Feb 2009 */ static const char *temp_dir(){ -#if defined(WIN32) || defined(DJGPP) +#if defined(_WIN32) || defined(_WIN64) || defined(DJGPP) char *tmp; tmp = getenv("TEMP"); if ( tmp==NULL ) { diff --git a/pyframe3dd/src/py_HPGmatrix.c b/pyframe3dd/src/py_HPGmatrix.c index 1603b5b..df90ce0 100644 --- a/pyframe3dd/src/py_HPGmatrix.c +++ b/pyframe3dd/src/py_HPGmatrix.c @@ -299,11 +299,10 @@ void ldl_mprove( ){ double sdp; /* accumulate the r.h.s. in double precision */ double *resid, /* the residual error */ - rms_resid_new=0, /* the RMS error of the mprvd solution */ - *dvector(); /* allocate memory for a vector of doubles */ + rms_resid_new=0; /* the RMS error of the mprvd solution */ + //*dvector(); /* allocate memory for a vector of doubles */ int j,i, pd; - void ldl_dcmp(), - free_dvector(); + //void ldl_dcmp(), free_dvector(); resid = dvector(1,n); @@ -492,11 +491,10 @@ void ldl_mprove_pm ( double sdp; // accumulate the r.h.s. in double precision double *dx, // the residual error *dc, // update to partial r.h.s. vector, c - rms_resid_new=0.0, // the RMS error of the mprvd solution - *dvector(); // allocate memory for a vector of doubles + rms_resid_new=0.0; // the RMS error of the mprvd solution + //*dvector(); // allocate memory for a vector of doubles int j,i, pd; - void ldl_dcmp(), - free_dvector(); + //void ldl_dcmp(), free_dvector(); dx = dvector(1,n); dc = dvector(1,n); @@ -581,10 +579,10 @@ void PSB_update ( void pseudo_inv( double **A, double **Ai, int n, int m, double beta, int verbose ){ - double *diag, *b, *x, **AtA, **AtAi, tmp, tr_AtA=0.0, - *dvector(), **dmatrix(), error; + double *diag, *b, *x, **AtA, **AtAi, tmp, tr_AtA=0.0, error; + //*dvector(), **dmatrix(), int i,j,k, ok; - void ldl_dcmp(), ldl_mprove(), free_dvector(), free_dmatrix(); + //void ldl_dcmp(), ldl_mprove(), free_dvector(), free_dmatrix(); diag = dvector(1,n); b = dvector(1,n); diff --git a/pyframe3dd/src/py_frame3dd.c b/pyframe3dd/src/py_frame3dd.c index 8989a3a..355d2bb 100644 --- a/pyframe3dd/src/py_frame3dd.c +++ b/pyframe3dd/src/py_frame3dd.c @@ -696,10 +696,10 @@ void assemble_M( float *NMs, float *NMx, float *NMy, float *NMz, int lump, int debug ){ - double **m, /* element mass matrix in global coord */ - **dmatrix(); + double **m; /* element mass matrix in global coord */ + //**dmatrix(); int **ind, /* member-structure DoF index table */ - **imatrix(), + //**imatrix(), res=0, i, j, ii, jj, l, ll; char mass_fn[FILENMAX]; @@ -1109,7 +1109,7 @@ void deallocate( ){ - void free(); + //void free(); free(xyz); diff --git a/pyproject.toml b/pyproject.toml index a37e3eb..5b69139 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,129 @@ [build-system] -requires = [ - "setuptools>=42", - "meson>=0.60.0", - "ninja", -] +requires = ["setuptools", "meson>=1.1", "ninja", "wheel"] build-backend = "setuptools.build_meta" -# "ninja; platform_system!='Windows'", + +[project] +name = "WISDEM-pyFrame3DD" +version = "1.0.1" +description = "Python bindings to Frame3DD, a code for static and dynamic structural analysis of 2D and 3D frames and trusses, with permission from Prof Henri Gavin" +readme = "README.md" +requires-python = ">=3.9" +license = {text = "Apache-2.0"} +keywords = ["wind", "turbine", "mdao", "design", "optimization"] +authors = [ + {name = "NREL WISDEM Team", email = "systems.engineering@nrel.gov" } +] +maintainers = [ + {name = "NREL WISDEM Team", email = "systems.engineering@nrel.gov" } +] +classifiers = [ # Optional + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + "Development Status :: 4 - Beta", + + # Indicate who your project is intended for + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering", + + "License :: OSI Approved :: Apache Software License", + + # Specify the Python versions you support here. In particular, ensure + # that you indicate you support Python 3. These classifiers are *not* + # checked by "pip install". See instead "python_requires" below. + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Fortran", +] + +dependencies = [ + "numpy", +] + +# List additional groups of dependencies here (e.g. development +# dependencies). Users will be able to install these using the "extras" +# syntax, for example: +# +# $ pip install sampleproject[dev] +# +# Similar to `dependencies` above, these must be valid existing +# projects. +[project.optional-dependencies] # Optional +dev = ["meson", "ninja"] +test = ["pytest"] + +# List URLs that are relevant to your project +# +# This field corresponds to the "Project-URL" and "Home-Page" metadata fields: +# https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use +# https://packaging.python.org/specifications/core-metadata/#home-page-optional +# +# Examples listed include a pattern for specifying where the package tracks +# issues, where the source is hosted, where to say thanks to the package +# maintainers, and where to support the project financially. The key is +# what's used to render the link text on PyPI. +[project.urls] # Optional +"Homepage" = "https://github.com/WISDEM/pyFrame3DD" +"Project" = "https://frame3dd.sourceforge.net" + +# This is configuration specific to the `setuptools` build backend. +# If you are using a different build backend, you will need to change this. +[tool.setuptools] +zip-safe = false +include-package-data = true + +#[tool.setuptools.packages] +#find = {} + +[tool.setuptools.packages.find] +#where = ["wisdem"] +exclude = ["test", "examples"] +namespaces = true + +[tool.setuptools.package-data] +# If there are data files included in your packages that need to be +# installed, specify them here. +"*" = ["*.so", "*.lib", "*.pyd", "*.pdb", "*.dylib", "*.dll"] + +[tool.black] +line-length = 120 +target-version = ['py39'] +include = '\.pyi?$' +exclude = ''' +/( + \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist +)/ +''' + +[tool.isort] +# https://github.com/PyCQA/isort +multi_line_output = "3" +include_trailing_comma = true +force_grid_wrap = false +use_parentheses = true +line_length = "120" +sections = ["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER"] +known_first_party = ["wisdem"] +length_sort = "1" +profile = "black" +skip_glob = ['__init__.py'] +atomic = true +#lines_after_imports = 2 +#lines_between_types = 1 +#src_paths=isort,test + +[tool.cibuildwheel] +skip = ["cp36-*", "cp37-*", "cp38-*", "*-win32", "*arm64", "pp*"] +build-frontend = "build" diff --git a/setup.py b/setup.py index a59d3bd..c0e1d0b 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,6 @@ +#!/usr/bin/env python +# encoding: utf-8 + # setup.py # only if building in place: ``python setup.py build_ext --inplace`` import os @@ -7,6 +10,22 @@ import setuptools import subprocess +####### +# This forces wheels to be platform specific +from setuptools.dist import Distribution +from wheel.bdist_wheel import bdist_wheel as _bdist_wheel + +class bdist_wheel(_bdist_wheel): + def finalize_options(self): + _bdist_wheel.finalize_options(self) + self.root_is_pure = False + +class BinaryDistribution(Distribution): + """Distribution which always forces a binary package with platform name""" + def has_ext_modules(foo): + return True +####### + def run_meson_build(staging_dir): prefix = os.path.join(os.getcwd(), staging_dir) @@ -16,6 +35,8 @@ def run_meson_build(staging_dir): meson_args = "" if "MESON_ARGS" in os.environ: meson_args = os.environ["MESON_ARGS"] + # A weird add-on on mac github action runners needs to be removed + if meson_args.find("buildtype") >= 0: meson_args = "" if platform.system() == "Windows": if not "FC" in os.environ: @@ -25,14 +46,15 @@ def run_meson_build(staging_dir): # configure meson_path = shutil.which("meson") - meson_call = ( - f"{meson_path} setup {staging_dir} --prefix={prefix} " - + f"-Dpython.purelibdir={purelibdir} -Dpython.platlibdir={purelibdir} {meson_args}" - ) - sysargs = meson_call.split(" ") - sysargs = [arg for arg in sysargs if arg != ""] - print(sysargs) - p1 = subprocess.run(sysargs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if meson_path is None: + raise OSError("The meson command cannot be found on the system") + + meson_call = [meson_path, "setup", staging_dir, "--wipe", + f"--prefix={prefix}", f"-Dpython.purelibdir={purelibdir}", + f"-Dpython.platlibdir={purelibdir}", meson_args] + meson_call = [m for m in meson_call if m != ""] + print(meson_call) + p1 = subprocess.run(meson_call, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) os.makedirs(staging_dir, exist_ok=True) setup_log = os.path.join(staging_dir, "setup.log") with open(setup_log, "wb") as f: @@ -40,23 +62,20 @@ def run_meson_build(staging_dir): if p1.returncode != 0: with open(setup_log, "r") as f: print(f.read()) - raise OSError(sysargs, f"The meson setup command failed! Check the log at {setup_log} for more information.") + raise OSError(meson_call, f"The meson setup command failed! Check the log at {setup_log} for more information.") # build - meson_call = f"{meson_path} compile -vC {staging_dir}" - sysargs = meson_call.split(" ") - sysargs = [arg for arg in sysargs if arg != ""] - print(sysargs) - p2 = subprocess.run(sysargs, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + meson_call = [meson_path, "compile", "-vC", staging_dir] + meson_call = [m for m in meson_call if m != ""] + print(meson_call) + p2 = subprocess.run(meson_call, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) compile_log = os.path.join(staging_dir, "compile.log") with open(compile_log, "wb") as f: f.write(p2.stdout) if p2.returncode != 0: with open(compile_log, "r") as f: print(f.read()) - raise OSError( - sysargs, f"The meson compile command failed! Check the log at {compile_log} for more information." - ) + raise OSError(meson_call, f"The meson compile command failed! Check the log at {compile_log} for more information.") def copy_shared_libraries(): @@ -64,7 +83,7 @@ def copy_shared_libraries(): for root, _dirs, files in os.walk(build_path): for file in files: # move pyframe3dd to just under staging_dir - if file.endswith((".so", ".lib", ".pyd", ".pdb", ".dylib", ".dll")): + if file.endswith((".so", ".lib", ".pyd", ".pdb", ".dylib", ".dll", ".mod")): if ".so.p" in root or ".pyd.p" in root: # excludes intermediate object files continue file_path = os.path.join(root, file) @@ -72,7 +91,7 @@ def copy_shared_libraries(): match = re.search(staging_dir, new_path) new_path = new_path[match.span()[1] + 1 :] print(f"Copying build file {file_path} -> {new_path}") - shutil.copy(file_path, new_path) + shutil.move(file_path, new_path) if __name__ == "__main__": @@ -87,53 +106,12 @@ def copy_shared_libraries(): os.chdir(cwd) copy_shared_libraries() - #docs_require = "" - #req_txt = os.path.join("doc", "requirements.txt") - #if os.path.isfile(req_txt): - # with open(req_txt) as f: - # docs_require = f.read().splitlines() - init_file = os.path.join("pyframe3dd", "__init__.py") #__version__ = re.findall( # r"""__version__ = ["']+([0-9\.]*)["']+""", # open(init_file).read(), #)[0] - setuptools.setup( - name="pyFrame3DD", - version="1.2", - description="Python bindings to Frame3DD", - long_description="pyFrame3DD is a Python package that provides a library-like interface to the structural analysis program, Frame3DD", - author='NREL WISDEM Team', - author_email='systems.engineering@nrel.gov', - install_requires=[ - "numpy", - ], - extras_require={ - "testing": ["pytest"], - }, - python_requires=">=3.8", - packages=["pyframe3dd"], - package_data={"": ["*.yaml", "*.so", "*.lib", "*.pyd", "*.pdb", "*.dylib", "*.dll"]}, - license='Apache License, Version 2.0', - zip_safe=False, - ) + setuptools.setup(cmdclass={'bdist_wheel': bdist_wheel}, distclass=BinaryDistribution) #os.environ['NPY_DISTUTILS_APPEND_FLAGS'] = '1' - -#if os.name == 'nt': # Windows. -# extra_compile_args = ['/TC', '/D', 'ANSI'] # for msvs -# # TODO: Not with Anaconda MINGW -#else: -#extra_compile_args = '' - -#froot = 'pyframe3dd' + os.sep + 'src' + os.sep -#pyframeExt = Extension('pyframe3dd._pyframe3dd', sources=[froot+'py_HPGmatrix.c', -# froot+'HPGutil.c', -# froot+'NRutil.c', -# froot+'coordtrans.c', -# froot+'preframe.c', -# froot+'py_eig.c', -# froot+'py_frame3dd.c', -# froot+'py_io.c', -# froot+'py_main.c'])