Menu

SVN archive Commit Log


Commit Date  
[r25256] by tlinnet

Intermediate step in estimate R2eff module.

It seems that minfx is minimising in a quadratic space because of the power of chi2, while
the general input to scipy.optimize does not do this.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.

2014-08-25 21:00:39 Tree
[r25255] by tlinnet

Tried algorithms:

newton
Newton-CG
Steepest descent
Fletcher-Reeves

None of them work.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.

2014-08-25 18:57:15 Tree
[r25254] by tlinnet

Initial try to form the Jacobian and Hessian matrix for exponential decay.

This can be tried with systemtest:
relax -s Relax_disp.test_estimate_r2eff_error

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.

2014-08-25 18:03:40 Tree
[r25253] by bugman

Merged revisions 25230-25251 via svnmerge from
svn+ssh://bugman@.../svn/relax/trunk

........
r25230 | tlinnet | 2014-08-25 01:08:48 +0200 (Mon, 25 Aug 2014) | 3 lines

Moved the target function for minimisation of exponential fit into the target functions folder.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25231 | tlinnet | 2014-08-25 01:08:50 +0200 (Mon, 25 Aug 2014) | 3 lines

Implemented initial systemtest Relax_disp.test_estimate_r2eff for setting up the new user function to estimate R2eff and errors by scipy.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25232 | tlinnet | 2014-08-25 01:08:53 +0200 (Mon, 25 Aug 2014) | 3 lines

Added front end user function relax_disp.r2eff_estimate() to estimate R2eff and errors by exponential curve fitting in scipy.optimize.leastsq.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25233 | tlinnet | 2014-08-25 01:08:55 +0200 (Mon, 25 Aug 2014) | 3 lines

Modified check for model, to accept model as input, for error printing.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25234 | tlinnet | 2014-08-25 01:08:57 +0200 (Mon, 25 Aug 2014) | 3 lines

Implemented back end for estimating r2eff and errors by exponential curve fitting with scipy.optimize.leastsq.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25235 | tlinnet | 2014-08-25 01:08:58 +0200 (Mon, 25 Aug 2014) | 5 lines

Documentation fix for new exponential target function.

Also added new function to estimate R2eff and i0 parameters, before minimisation.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25236 | tlinnet | 2014-08-25 01:09:00 +0200 (Mon, 25 Aug 2014) | 3 lines

Small changes to verification scripts, to use chi2 function and use the scaling matrix correct.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25237 | tlinnet | 2014-08-25 01:09:02 +0200 (Mon, 25 Aug 2014) | 6 lines

Split up of systemtest test_r1rho_kjaergaard_missing_r1, into a verification part.

This is to test the new r2eff estimation, which should get the parameter values, as a
this 2000 monto carlo simulation.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25238 | tlinnet | 2014-08-25 01:32:13 +0200 (Mon, 25 Aug 2014) | 56 lines

Modified systemtest Relax_disp.test_estimate_r2eff.

This is to compare against errors simulated with 2000 MC.

The paramaters are comparable, but not equal.
Mostly, it seems that the errors from scipy.optimize.leastsq, are twice as high than the Monte Carlo simulations.
This affect model fitting, and the calculated chi2 value.

Left column is 2000 Monte Carlo, right column is scipy.optimize.leastsq.

Optimised parameters for spin: 52V @N
Model: No Rex
Parameter: r1 Value: 1.46138806 - 1.46328102
Parameter: r2 Value: 11.48392438 - 11.48040934
Parameter: chi2 Value: 848.42015672 - 3363.95829122

Model: DPL94
Parameter: r1 Value: 1.44845743 - 1.45019848
Parameter: r2 Value: 10.15688373 - 10.16304892
Parameter: phi_ex Value: 0.07599563 - 0.07561937
Parameter: kex Value: 4460.43707304 - 4419.03906628
Parameter: chi2 Value: 179.47041255 - 710.24767560

Model: TP02
Parameter: r1 Value: 1.54354392 - 1.54352369
Parameter: r2 Value: 9.72654895 - 9.72772727
Parameter: pA Value: 0.88827039 - 0.88807488
Parameter: dw Value: 1.08875836 - 1.08765645
Parameter: kex Value: 4921.28597928 - 4904.70134941
Parameter: chi2 Value: 29.33882481 - 114.47142772

Model: TAP03
Parameter: r1 Value: 1.54356410 - 1.54354368
Parameter: r2 Value: 9.72641885 - 9.72759371
Parameter: pA Value: 0.88828925 - 0.88809317
Parameter: dw Value: 1.08837248 - 1.08726695
Parameter: kex Value: 4926.42974479 - 4909.86896567
Parameter: chi2 Value: 29.29050624 - 114.27987534

Model: MP05
Parameter: r1 Value: 1.54356415 - 1.54354372
Parameter: r2 Value: 9.72641730 - 9.72759220
Parameter: pA Value: 0.88828927 - 0.88809322
Parameter: dw Value: 1.08837250 - 1.08726707
Parameter: kex Value: 4926.44228958 - 4909.88128236
Parameter: chi2 Value: 29.29054252 - 114.28002272

Model: NS R1rho 2-site
Parameter: r1 Value: 1.41359226 - 1.41321968
Parameter: r2 Value: 9.34531364 - 9.34602793
Parameter: pA Value: 0.94504369 - 0.94496541
Parameter: dw Value: 1.56001843 - 1.55833321
Parameter: kex Value: 5628.66529504 - 5610.20221435
Parameter: chi2 Value: 34.44010458 - 134.14368365

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25239 | tlinnet | 2014-08-25 01:50:58 +0200 (Mon, 25 Aug 2014) | 47 lines

Added systemtest Relax_disp.test_estimate_r2eff_error().

This is to get insight in the error difference between 2000 monto carlo simulations and then scipy.optimize.leastsq.

R1rho at 799.8 MHz, for offset=118.078 ppm and dispersion point 431.0.
r2eff=8.646/8.646 r2eff_err=0.0348/0.0692 i0=202664.191/202664.191 i0_err=699.6443/712.4201

R1rho at 799.8 MHz, for offset=118.078 ppm and dispersion point 651.2.
r2eff=10.377/10.377 r2eff_err=0.0403/0.0810 i0=206049.558/206049.558 i0_err=776.4215/782.1833

R1rho at 799.8 MHz, for offset=118.078 ppm and dispersion point 800.5.
r2eff=10.506/10.506 r2eff_err=0.0440/0.0853 i0=202586.332/202586.332 i0_err=763.9678/758.7052

R1rho at 799.8 MHz, for offset=118.078 ppm and dispersion point 984.0.
r2eff=10.903/10.903 r2eff_err=0.0476/0.0922 i0=203455.021/203455.021 i0_err=837.8779/828.7280

R1rho at 799.8 MHz, for offset=118.078 ppm and dispersion point 1341.1.
r2eff=10.684/10.684 r2eff_err=0.0446/0.0853 i0=218670.412/218670.411 i0_err=850.0210/830.9558

R1rho at 799.8 MHz, for offset=118.078 ppm and dispersion point 1648.5.
r2eff=10.501/10.501 r2eff_err=0.0371/0.0742 i0=206502.512/206502.512 i0_err=794.0523/772.9843

R1rho at 799.8 MHz, for offset=124.247 ppm and dispersion point 1341.1.
r2eff=11.118/11.118 r2eff_err=0.0413/0.0827 i0=216447.241/216447.241 i0_err=784.6562/788.0384

R1rho at 799.8 MHz, for offset=130.416 ppm and dispersion point 800.5.
r2eff=7.866/7.866 r2eff_err=0.0347/0.0695 i0=211869.715/211869.715 i0_err=749.2776/763.6930

R1rho at 799.8 MHz, for offset=130.416 ppm and dispersion point 1341.1.
r2eff=9.259/9.259 r2eff_err=0.0331/0.0661 i0=217703.151/217703.151 i0_err=682.2137/685.5838

R1rho at 799.8 MHz, for offset=130.416 ppm and dispersion point 1648.5.
r2eff=9.565/9.565 r2eff_err=0.0373/0.0745 i0=211988.939/211988.939 i0_err=839.0313/827.0373

R1rho at 799.8 MHz, for offset=142.754 ppm and dispersion point 800.5.
r2eff=3.240/3.240 r2eff_err=0.0127/0.0253 i0=214417.382/214417.382 i0_err=595.8865/613.4378

R1rho at 799.8 MHz, for offset=142.754 ppm and dispersion point 1341.1.
r2eff=5.084/5.084 r2eff_err=0.0177/0.0352 i0=226358.691/226358.691 i0_err=660.5314/655.7670

R1rho at 799.8 MHz, for offset=179.768 ppm and dispersion point 1341.1.
r2eff=2.208/2.208 r2eff_err=0.0091/0.0178 i0=228620.553/228620.553 i0_err=564.8353/560.0873

R1rho at 799.8 MHz, for offset=241.459 ppm and dispersion point 1341.1.
r2eff=1.711/1.711 r2eff_err=0.0077/0.0155 i0=224087.486/224087.486 i0_err=539.4300/546.4217

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25240 | tlinnet | 2014-08-25 12:06:29 +0200 (Mon, 25 Aug 2014) | 3 lines

Add dependency check for scipy.optimize.leastsq.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25241 | tlinnet | 2014-08-25 12:26:21 +0200 (Mon, 25 Aug 2014) | 5 lines

Lowering precision in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.

This is R1 estimation with: MODEL_NS_R1RHO_2SITE.

The lowering of precision is due different system precision.
........
r25242 | tlinnet | 2014-08-25 12:31:52 +0200 (Mon, 25 Aug 2014) | 1 line

Re-used the dependency check "scipy_module", since leastsq() has been part of Scipy since 2003.
........
r25243 | tlinnet | 2014-08-25 13:27:41 +0200 (Mon, 25 Aug 2014) | 8 lines

Moved target function for curve fitting with scipy into specific_analyses.relax_disp.estimate_r2eff.

This will later include the backend specific_analyses.relax_disp.optimisation.estimate_r2eff()
function and the code in the target_functions package.

The code in target_functions.relax_disp_curve_fit is a lot more than just a target function, so it doesn't really belong in this package.

This is also to isolate this experimental feature.
........
r25244 | tlinnet | 2014-08-25 13:27:43 +0200 (Mon, 25 Aug 2014) | 5 lines

Isolated all code related to user function:

relax_disp.r2eff_estimate() into independent module file.

All has been isolated to: specific_analyses.relax_disp.estimate_r2eff.
........
r25245 | tlinnet | 2014-08-25 15:22:55 +0200 (Mon, 25 Aug 2014) | 3 lines

Split function to minimise with scipy.optimize.leastsq out in estimate_r2eff module.

This is to prepare for implementing with minfx.
........
r25246 | tlinnet | 2014-08-25 15:22:57 +0200 (Mon, 25 Aug 2014) | 3 lines

Implemented first try to minimise with minfx in estimate_r2eff() function.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25247 | tlinnet | 2014-08-25 15:27:49 +0200 (Mon, 25 Aug 2014) | 3 lines

Fix for missing imports.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25248 | tlinnet | 2014-08-25 15:27:51 +0200 (Mon, 25 Aug 2014) | 3 lines

Removal of unnecessary imports in specific_analyses.relax_disp.optimisation().

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.
........
r25249 | bugman | 2014-08-25 15:28:43 +0200 (Mon, 25 Aug 2014) | 14 lines

Implementation of the target_functions.relax_fit.jacobian() function.

This follows from the discussions at http://thread.gmane.org/gmane.science.nmr.relax.devel/6807.

The function will calculate the Jacobian matrix for the exponential curve-fitting module. The
Jacobian can be used to directly calculate the covariance matrix, for example as described at
https://www.gnu.org/software/gsl/manual/html_node/Computing-the-covariance-matrix-of-best-fit-parameters.html.
The Jacobian is calculated using the help of the new exponential_dI() and exponential_dR() functions
in the target_functions/exponential.c file. These calculate the partial derivatives of the
exponential curve with respect to each model parameter separately.

The implementation still needs testing and debugging.
........
r25250 | bugman | 2014-08-25 16:09:16 +0200 (Mon, 25 Aug 2014) | 5 lines

Fixes for the new target_functions.relax_fit.jacobian() function.

The Python list of lists is now correctly created and returned.
........
r25251 | bugman | 2014-08-25 17:10:57 +0200 (Mon, 25 Aug 2014) | 8 lines

Turned off the optimisation constraints for the 'R2eff' model in the dispersion auto-analysis.

This follows from http://thread.gmane.org/gmane.science.nmr.relax.scm/22977/focus=6829.

This model does not require constraints at all, and the constraints only cause the optimisation to
take 10x longer to complete. Therefore the constraint flag has been set to False for the model.
........

2014-08-25 16:03:34 Tree
[r25252] by bugman

Merged revisions 25214-25221,25223-25229 via svnmerge from
svn+ssh://bugman@.../svn/relax/trunk

........
r25214 | tlinnet | 2014-08-22 14:48:11 +0200 (Fri, 22 Aug 2014) | 21 lines

Modified following functions:

Time points are now saved at the [ei][mi][oi][di] index level.
At this index Ãlevelall time points are saved for the R2eff point.

- interpolate_disp()
To interpolate time points, all time points through the original dispersion points di, are
collected and then made unique. This time list can potentially be the largest of all time lists.

- interpolate_offset()
To interpolate time points, all time points through the original offset points, and then dispersion points di, are
collected and then made unique. This time list can potentially be the largest of all time lists.

- plot_disp_curves_to_file()
To acquire the original relax_times points.

- return_r2eff_arrays()
To save all time points on the level of [ei][mi][oi][di].
At this index level, it will be a numpy array list with all time values used for fitting.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25215 | tlinnet | 2014-08-22 14:48:18 +0200 (Fri, 22 Aug 2014) | 3 lines

Modified back_calc_r2eff() to accept interpolated timepoints.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25216 | tlinnet | 2014-08-22 14:48:19 +0200 (Fri, 22 Aug 2014) | 3 lines

Modified target function of relax disp, to use the the new list of time points, which are of higher dimension.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25217 | tlinnet | 2014-08-22 14:48:21 +0200 (Fri, 22 Aug 2014) | 8 lines

Fix to systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1()

After the relaxation times have been fixed, this model now return reasonable chi2 values.

The reported parameters are though quite different from all other models, and it seems something may
still be wrong.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25218 | tlinnet | 2014-08-22 14:53:25 +0200 (Fri, 22 Aug 2014) | 3 lines

Fix for time not extracted for CPMG experiments in target_function-

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25219 | tlinnet | 2014-08-22 15:22:36 +0200 (Fri, 22 Aug 2014) | 3 lines

Fix for interpolating time points, when producing xmgrace files for CPMG experiments.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25220 | tlinnet | 2014-08-22 15:22:38 +0200 (Fri, 22 Aug 2014) | 5 lines

Fix for systemtest Relax_disp.test_exp_fit(), where the spin.isotope was not set.

The new call to return_r2eff_arrays(), when producing graphs, raise RelaxSpinTypeError() if no isotope is set.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25221 | bugman | 2014-08-22 15:50:08 +0200 (Fri, 22 Aug 2014) | 5 lines

Modified the Relax_disp.test_r1rho_kjaergaard_missing_r1 system test to pass on 64-bit Linux systems.

The accuracy of the checks of the optimised values have been decreased.
........
r25223 | tlinnet | 2014-08-22 16:27:19 +0200 (Fri, 22 Aug 2014) | 3 lines

Moved the storing of relax time up before check of missing data in return_r2eff_arrays().

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25224 | tlinnet | 2014-08-22 16:27:23 +0200 (Fri, 22 Aug 2014) | 3 lines

Fix for systemtest not adding spin.isotope to setup information.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25225 | tlinnet | 2014-08-22 16:27:25 +0200 (Fri, 22 Aug 2014) | 3 lines

Fix for looping over data indices, where tilt_angles has the si index.

bug #22461(https://gna.org/bugs/?22461): NS R1rho 2-site_fit_r1 has extremely high chi2 value in systemtest Relax_disp.test_r1rho_kjaergaard_missing_r1.
........
r25226 | bugman | 2014-08-22 19:00:56 +0200 (Fri, 22 Aug 2014) | 6 lines

Added Nikolai's original Matlab code to the lib.dispersion.ns_r1rho_2site module docstring.

This is the code taken directly form the original funNumrho.m file, which was the origin of the code
in this module.
........
r25227 | tlinnet | 2014-08-22 19:17:19 +0200 (Fri, 22 Aug 2014) | 7 lines

Further extended the profiling script for curve fitting.

Now profiling is in place for the implemented C code method in relax.

A similar code should now be devised for numpy array for comparing.

But this profiling shows that when contraints=True, is slowing down this procedure by a factor 10 X !
........
r25228 | tlinnet | 2014-08-25 01:08:44 +0200 (Mon, 25 Aug 2014) | 12 lines

Further improved the profiling of relax curve fit.

This profiling shows, that Python code is about twice as slow as the C code implemented.

But it also shows that optimising with scipy.optimize.leastsq is 20 X faster.
It also gives reasonable error values.

Combining a function for a linear fit to guess the initial values, together
with scipy optimise, will be an extreme time win for estimating R2eff values fast.

A further test would be to use relax Monte-Carlo simulations for say 1000-2000 iterations,
and compare to the errors extracted from estimated covariance.
........
r25229 | tlinnet | 2014-08-25 01:08:46 +0200 (Mon, 25 Aug 2014) | 31 lines

Added verification script, that shows that using scipy.optimize.leastsq reaches the exact same parameters as minfx for exponential curve fitting.

The profiling shows that scipy.optimize.leastsq is 10X as fast as using minfx (with no linear constraints.)
scipy.optimize.leastsq is a wrapper around wrapper around MINPACK's lmdif and lmder algorithms.

MINPACK is a FORTRAN90 library which solves systems of nonlinear equations, or carries out the least squares minimization of the residual of a set of linear or nonlinear equations.

The verification script also shows, that a very heavy and time consuming monte carlo simulation of 2000 steps, reaches the same
errors as the errors reported by scipy.optimize.leastsq.

The return from scipy.optimize.leastsq, gives the estimated co-variance.
Taking the square root of the co-variance corresponds with 2X error reported by minfx.

This could be an extremely time saving step, when performing model fitting in R1rho, where
the errors of the R2eff values, are estimited by Monte-Carlo simulations.

The following setup illustrates the problem.
This was analysed on a: MacBook Pro, 13-inch, Late 2011.
Witn no multi-core setup.

Script running is:
test_suite/shared_data/dispersion/Kjaergaard_et_al_2013/2_pre_run_r2eff.py

This script analyses just the R2eff values for 15 residues.
It estimates the errors of R2eff based on 2000 Monte Carlo simulations.
For each residues, there is 14 exponential graphs.

The script was broken after 35 simulations.
This was measured to 20 minutes.
So 500 simulations would take about 4.8 Hours.
The R2eff values and errors can by scipy.optimize.leastsq can instead be calculated in: 15 residues * 0.02 seconds = 0.3 seconds.
........

2014-08-25 15:57:22 Tree
[r25251] by bugman

Turned off the optimisation constraints for the 'R2eff' model in the dispersion auto-analysis.

This follows from http://thread.gmane.org/gmane.science.nmr.relax.scm/22977/focus=6829.

This model does not require constraints at all, and the constraints only cause the optimisation to
take 10x longer to complete. Therefore the constraint flag has been set to False for the model.

2014-08-25 15:10:57 Tree
[r25250] by bugman

Fixes for the new target_functions.relax_fit.jacobian() function.

The Python list of lists is now correctly created and returned.

2014-08-25 14:09:16 Tree
[r25249] by bugman

Implementation of the target_functions.relax_fit.jacobian() function.

This follows from the discussions at http://thread.gmane.org/gmane.science.nmr.relax.devel/6807.

The function will calculate the Jacobian matrix for the exponential curve-fitting module. The
Jacobian can be used to directly calculate the covariance matrix, for example as described at
https://www.gnu.org/software/gsl/manual/html_node/Computing-the-covariance-matrix-of-best-fit-parameters.html.
The Jacobian is calculated using the help of the new exponential_dI() and exponential_dR() functions
in the target_functions/exponential.c file. These calculate the partial derivatives of the
exponential curve with respect to each model parameter separately.

The implementation still needs testing and debugging.

2014-08-25 13:28:43 Tree
[r25248] by tlinnet

Removal of unnecessary imports in specific_analyses.relax_disp.optimisation().

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.

2014-08-25 13:27:51 Tree
[r25247] by tlinnet

Fix for missing imports.

task #7822(https://gna.org/task/index.php?7822): Implement user function to estimate R2eff and associated errors for exponential curve fitting.

2014-08-25 13:27:49 Tree
Older >
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.