• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcuntz / pyjams / 6908420384

17 Nov 2023 07:48PM UTC coverage: 26.964% (-68.5%) from 95.437%
6908420384

push

github

mcuntz
Split ncread and ncinfo in separate files

1 of 4 new or added lines in 1 file covered. (25.0%)

936 existing lines in 13 files now uncovered.

357 of 1324 relevant lines covered (26.96%)

1.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.0
/src/pyjams/functions/logistic_function.py
1
#!/usr/bin/env python
2
"""
4✔
3
Several forms of the logistic function and their first and second derivatives
4

5
The current functions are the following. Each function has a second form with
6
`_p` appended to the name, where parameters are given as an iterable, e.g.
7
`logistic` and `logistic_p` = `logistic(x, *p)`:
8

9
.. list-table::
10
   :widths: 15 50
11
   :header-rows: 1
12

13
   * - Function
14
     - Description
15
   * - logistic
16
     - Logistic function `L/(1+exp(-k(x-x0)))`
17
   * - dlogistic
18
     - First derivative of logistic function
19
   * - d2logistic
20
     - Second derivative of logistic function
21
   * - logistic_offset
22
     - logistic function with offset `L/(1+exp(-k(x-x0))) + a`
23
   * - dlogistic_offset
24
     - First derivative of logistic function with offset
25
   * - d2logistic_offset
26
     - Second derivative of logistic function with offset
27
   * - logistic2_offset
28
     - Double logistic function with offset
29
       `L1/(1+exp(-k1(x-x01))) - L2/(1+exp(-k2(x-x02))) + a`
30
   * - dlogistic2_offset
31
     - First derivative of double logistic function with offset
32
   * - d2logistic2_offset
33
     - Second derivative of double logistic function with offset
34

35
This module was written by Matthias Cuntz while at Department of
36
Computational Hydrosystems, Helmholtz Centre for Environmental
37
Research - UFZ, Leipzig, Germany, and continued while at Institut
38
National de Recherche pour l'Agriculture, l'Alimentation et
39
l'Environnement (INRAE), Nancy, France.
40

41
:copyright: Copyright 2015-2022 Matthias Cuntz, see AUTHORS.rst for details.
42
:license: MIT License, see LICENSE for details.
43

44
.. moduleauthor:: Matthias Cuntz
45

46
Functions:
47

48
.. autosummary::
49
   logistic
50
   logistic_p
51
   dlogistic
52
   dlogistic_p
53
   d2logistic
54
   d2logistic_p
55
   logistic_offset
56
   logistic_offset_p
57
   dlogistic_offset
58
   dlogistic_offset_p
59
   d2logistic_offset
60
   d2logistic_offset_p
61
   logistic2_offset
62
   logistic2_offset_p
63
   dlogistic2_offset
64
   dlogistic2_offset_p
65
   d2logistic2_offset
66
   d2logistic2_offset_p
67

68
History
69
    * Written Mar 2015 by Matthias Cuntz (mc (at) macu (dot) de)
70
    * Added functions logistic_p and logistic_offset_p,
71
      Dec 2017, Matthias Cuntz
72
    * Changed to Sphinx docstring and numpydoc, Dec 2019, Matthias Cuntz
73
    * Distinguish iterable and array_like parameter types,
74
      Jan 2020, Matthias Cuntz
75
    * Make systematically function_p versions of all logistic functions and its
76
      derivatives, Feb 2020, Matthias Cuntz
77
    * Split logistic and curvature into separate files,
78
      May 2020, Matthias Cuntz
79
    * More consistent docstrings, Jan 2022, Matthias Cuntz
80

81
"""
82
import numpy as np
4✔
83
import scipy.special as sp
4✔
84

85

86
__all__ = ['logistic', 'logistic_p',
4✔
87
           'dlogistic', 'dlogistic_p',
88
           'd2logistic', 'd2logistic_p',
89
           'logistic_offset', 'logistic_offset_p',
90
           'dlogistic_offset', 'dlogistic_offset_p',
91
           'd2logistic_offset', 'd2logistic_offset_p',
92
           'logistic2_offset', 'logistic2_offset_p',
93
           'dlogistic2_offset', 'dlogistic2_offset_p',
94
           'd2logistic2_offset', 'd2logistic2_offset_p']
95

96

97
# -----------------------------------------------------------
98
# a/(1+exp(-b(x-c))) - logistic function
99
def logistic(x, L, k, x0):
4✔
100
    """
101
    Logistic function
102

103
    .. math::
104
       L/(1+exp(-k(x-x0)))
105

106
    Parameters
107
    ----------
108
    x : array_like
109
        Independent variable to evalute logistic function
110
    L : float
111
        Maximum of logistic function
112
    k : float
113
        Steepness of logistic function
114
    x0 : float
115
        Inflection point of logistic function
116

117
    Returns
118
    -------
119
    float or ndarray
120
        Logistic function at *x* with maximum *L*, steepness *k* and inflection
121
        point *x0*
122

123
    """
UNCOV
124
    return L * sp.expit(k * (x - x0))
×
125

126

127
def logistic_p(x, p):
4✔
128
    """
129
    Wrapper function for :func:`logistic`: `logistic(x, *p)`
130

131
    """
UNCOV
132
    return logistic(x, *p)
×
133

134

135
# -----------------------------------------------------------
136
# 1st derivative of logistic functions
137
def dlogistic(x, L, k, x0):
4✔
138
    """
139
    First derivative of :func:`logistic` function
140

141
    .. math::
142
       L/(1+exp(-k(x-x0)))
143

144
    which is
145

146
    .. math::
147
       k.L/(2(cosh(k(x-x0))+1))
148

149
    Parameters
150
    ----------
151
    x : array_like
152
        Independent variable to evalute derivative of logistic function
153
    L : float
154
        Maximum of logistic function
155
    k : float
156
        Steepness of logistic function
157
    x0 : float
158
        Inflection point of logistic function
159

160
    Returns
161
    -------
162
    float or ndarray
163
        First derivative of logistic function at *x* with maximum *L*,
164
        steepness *k* and inflection point *x0*
165

166
    """
UNCOV
167
    return k * L / (2. * (np.cosh(k * (x - x0)) + 1.))
×
168

169

170
def dlogistic_p(x, p):
4✔
171
    """
172
    Wrapper function for :func:`dlogistic`: `dlogistic(x, *p)`
173

174
    """
UNCOV
175
    return dlogistic(x, *p)
×
176

177

178
# -----------------------------------------------------------
179
# 2nd derivative of logistic functions
180
def d2logistic(x, L, k, x0):
4✔
181
    """
182
    Second derivative of :func:`logistic` function
183

184
    .. math::
185
       L/(1+exp(-k(x-x0)))
186

187
    which is
188

189
    .. math::
190
       -k^2.L.sinh(k(x-x0))/(2(cosh(k(x-x0))+1)^2)
191

192
    Parameters
193
    ----------
194
    x : array_like
195
        Independent variable to evalute derivative of logistic function
196
    L : float
197
        Maximum of logistic function
198
    k : float
199
        Steepness of logistic function
200
    x0 : float
201
        Inflection point of logistic function
202

203
    Returns
204
    -------
205
    float or ndarray
206
        Second derivative of logistic function at *x* with maximum *L*,
207
        steepness *k* and inflection point *x0*
208

209
    """
UNCOV
210
    return ( -k**2 * L * np.sinh(k * (x - x0)) /
×
211
             (2. * (np.cosh(k * (x - x0)) + 1.)**2) )
212

213

214
def d2logistic_p(x, p):
4✔
215
    """
216
    Wrapper function for :func:`d2logistic`: `d2logistic(x, *p)`
217

218
    """
UNCOV
219
    return d2logistic(x, *p)
×
220

221

222
# -----------------------------------------------------------
223
# L/(1+exp(-k(x-x0))) + a - logistic function with offset
224
def logistic_offset(x, L, k, x0, a):
4✔
225
    """
226
    Logistic function with offset
227

228
    .. math::
229
       L/(1+exp(-k(x-x0))) + a
230

231
    Parameters
232
    ----------
233
    x : array_like
234
        Independent variable to evalute logistic function
235
    L : float
236
        Maximum of logistic function
237
    k : float
238
        Steepness of logistic function
239
    x0 : float
240
        Inflection point of logistic function
241
    a : float
242
        Offset of logistic function
243

244
    Returns
245
    -------
246
    float or ndarray
247
        Logistic function at *x* with maximum *L*, steepness *k*, inflection
248
        point *x0* and offset *a*
249

250
    """
UNCOV
251
    return L * sp.expit(k * (x - x0)) + a
×
252

253

254
def logistic_offset_p(x, p):
4✔
255
    """
256
    Wrapper function for :func:`logistic_offset`: `logistic_offset(x, *p)`
257

258
    """
UNCOV
259
    return logistic_offset(x, *p)
×
260

261

262
# -----------------------------------------------------------
263
# 1st derivative of logistic functions with offset
264
def dlogistic_offset(x, L, k, x0, a):
4✔
265
    """
266
    First derivative of :func:`logistic_offset` function
267

268
    .. math::
269
       L/(1+exp(-k(x-x0))) + a
270

271
    which is
272

273
    .. math::
274
       k.L/(2(cosh(k(x-x0))+1))
275

276
    Parameters
277
    ----------
278
    x : array_like
279
        Independent variable to evalute derivative of logistic function
280
    L : float
281
        Maximum of logistic function
282
    k : float
283
        Steepness of logistic function
284
    x0 : float
285
        Inflection point of logistic function
286
    a : float
287
        Offset of logistic function
288

289
    Returns
290
    -------
291
    float or ndarray
292
        First derivative of logistic function with offset at *x* with maximum
293
        *L*, steepness *k*, inflection point *x0*, and offset *a*
294

295
    """
UNCOV
296
    return k * L / (2. * (np.cosh(k * (x - x0)) + 1.))
×
297

298

299
def dlogistic_offset_p(x, p):
4✔
300
    """
301
    Wrapper function for :func:`dlogistic_offset`: `dlogistic_offset(x, *p)`
302

303
    """
UNCOV
304
    return dlogistic_offset(x, *p)
×
305

306

307
# -----------------------------------------------------------
308
# 2nd derivative of logistic functions with offset
309
def d2logistic_offset(x, L, k, x0, a):
4✔
310
    """
311
    Second derivative of :func:`logistic_offset` function
312

313
    .. math::
314
       L/(1+exp(-k(x-x0))) + a
315

316
    which is
317

318
    .. math::
319
       -k^2.L.sinh(k(x-x0))/(2(cosh(k(x-x0))+1)^2)
320

321
    Parameters
322
    ----------
323
    x : array_like
324
        Independent variable to evalute derivative of logistic function
325
    L : float
326
        Maximum of logistic function
327
    k : float
328
        Steepness of logistic function
329
    x0 : float
330
        Inflection point of logistic function
331
    a : float
332
        Offset of logistic function
333

334
    Returns
335
    -------
336
    float or ndarray
337
        Second derivative of logistic function at *x* with maximum *L*,
338
        steepness *k*, inflection point *x0*, and offset *a*
339

340
    """
UNCOV
341
    return ( -k**2 * L * np.sinh(k * (x - x0)) /
×
342
             (2. * (np.cosh(k * (x - x0)) + 1.)**2) )
343

344

345
def d2logistic_offset_p(x, p):
4✔
346
    """
347
    Wrapper function for :func:`d2logistic_offset`: `d2logistic_offset(x, *p)`
348

349
    """
UNCOV
350
    return d2logistic_offset(x, *p)
×
351

352

353
# -----------------------------------------------------------
354
# L/(1+exp(-k(x-x0))) + a - logistic function with offset
355
def logistic2_offset(x, L1, k1, x01, L2, k2, x02, a):
4✔
356
    """
357
    Double logistic function with offset
358

359
    .. math::
360
       L1/(1+exp(-k1(x-x01))) - L2/(1+exp(-k2(x-x02))) + a
361

362
    Parameters
363
    ----------
364
    x : array_like
365
        Independent variable to evalute logistic function
366
    L1 : float
367
        Maximum of first logistic function
368
    k1 : float
369
        Steepness of first logistic function
370
    x01 : float
371
        Inflection point of first logistic function
372
    L2 : float
373
        Maximum of second logistic function
374
    k2 : float
375
        Steepness of second logistic function
376
    x02 : float
377
        Inflection point of second logistic function
378
    a : float
379
        Offset of double logistic function
380

381
    Returns
382
    -------
383
    float or ndarray
384
        Double Logistic function at *x*
385

386
    """
UNCOV
387
    return L1 * sp.expit(k1 * (x - x01)) - L2 * sp.expit(k2 * (x - x02)) + a
×
388

389

390
def logistic2_offset_p(x, p):
4✔
391
    """
392
    Wrapper function for :func:`logistic2_offset`: `logistic2_offset(x, *p)`
393

394
    """
UNCOV
395
    return logistic2_offset(x, *p)
×
396

397

398
# -----------------------------------------------------------
399
# 1st derivative of logistic functions with offset
400
def dlogistic2_offset(x, L1, k1, x01, L2, k2, x02, a):
4✔
401
    """
402
    First derivative of :func:`logistic2_offset` function
403

404
    .. math::
405
       L1/(1+exp(-k1(x-x01))) - L2/(1+exp(-k2(x-x02))) + a
406

407
    which is
408

409
    .. math::
410
       k1.L1/(2(cosh(k1(x-x01))+1)) - k2.L2/(2(cosh(k2(x-x02))+1))
411

412
    Parameters
413
    ----------
414
    x : array_like
415
        Independent variable to evalute logistic function
416
    L1 : float
417
        Maximum of first logistic function
418
    k1 : float
419
        Steepness of first logistic function
420
    x01 : float
421
        Inflection point of first logistic function
422
    L2 : float
423
        Maximum of second logistic function
424
    k2 : float
425
        Steepness of second logistic function
426
    x02 : float
427
        Inflection point of second logistic function
428
    a : float
429
        Offset of double logistic function
430

431
    Returns
432
    -------
433
    float or ndarray
434
        First derivative of double logistic function with offset at *x*
435

436
    """
UNCOV
437
    return ( k1 * L1 / (2. * (np.cosh(k1 * (x - x01)) + 1.)) -
×
438
             k2 * L2 / (2. * (np.cosh(k2 * (x - x02)) + 1.)) )
439

440

441
def dlogistic2_offset_p(x, p):
4✔
442
    """
443
    Wrapper function for :func:`dlogistic2_offset`: `dlogistic2_offset(x, *p)`
444

445
    """
UNCOV
446
    return dlogistic2_offset(x, *p)
×
447

448

449
# -----------------------------------------------------------
450
# 2nd derivative of logistic functions with offset
451
def d2logistic2_offset(x, L1, k1, x01, L2, k2, x02, a):
4✔
452
    """
453
    Second derivative of :func:`logistic_offset` function
454

455
    .. math::
456
       L1/(1+exp(-k1(x-x01))) - L2/(1+exp(-k2(x-x02))) + a
457

458
    which is
459

460
    .. math::
461
       - k1^2.L1.sinh(k1(x-x01)) / (2(cosh(k1(x-x01))+1)^2)
462
       + k2^2.L2.sinh(k2(x-x02)) / (2(cosh(k2(x-x02))+1)^2)
463

464
    Parameters
465
    ----------
466
    x : array_like
467
        Independent variable to evalute logistic function
468
    L1 : float
469
        Maximum of first logistic function
470
    k1 : float
471
        Steepness of first logistic function
472
    x01 : float
473
        Inflection point of first logistic function
474
    L2 : float
475
        Maximum of second logistic function
476
    k2 : float
477
        Steepness of second logistic function
478
    x02 : float
479
        Inflection point of second logistic function
480
    a : float
481
        Offset of double logistic function
482

483
    Returns
484
    -------
485
    float or ndarray
486
        Second derivative of double logistic function with offset at *x*
487

488
    """
UNCOV
489
    return ( -k1**2 * L1 * np.sinh(k1 * (x - x01)) /
×
490
             (2. * (np.cosh(k1 * (x - x01)) + 1.)**2) +
491
             k2**2 * L2 * np.sinh(k2 * (x - x02)) /
492
             (2. * (np.cosh(k2 * (x - x02)) + 1.)**2) )
493

494

495
def d2logistic2_offset_p(x, p):
4✔
496
    """
497
    Wrapper function for
498
    :func:`d2logistic2_offset`: `d2logistic2_offset(x, *p)`
499

500
    """
UNCOV
501
    return d2logistic2_offset(x, *p)
×
502

503

504
# -----------------------------------------------------------
505

506
if __name__ == '__main__':
507
    import doctest
508
    doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)
509

510
    # logistic(1., 1., 0., 2.)
511
    # # 0.5
512
    # logistic(1., 1., 2., 1.)
513
    # # 0.5
514
    # logistic(2., 1., 1., 1.)
515
    # # 1./(1.+np.exp(-1.))
516
    # # 0.7310585786300049
517
    # logistic_p(1., [1., 0., 2.])
518
    # logistic_p(1., [1., 2., 1.])
519
    # logistic_p(2., [1., 1., 1.])
520
    # logistic_offset(1., 1., 0., 2., 1.)
521
    # logistic_offset(1., 1., 2., 1., 1.)
522
    # # 1.5
523
    # logistic_offset(2., 1., 1., 1., 1.)
524
    # # 1./(1.+np.exp(-1.)) + 1.
525
    # # 1.7310585786300049
526
    # logistic_offset_p(1., [1., 0., 2., 1.])
527
    # logistic_offset_p(1., [1., 2., 1., 1.])
528
    # logistic_offset_p(2., [1., 1., 1., 1.])
529
    # logistic2_offset(1.,  1., 2., 1.,  2., 2., 1.,  1.)
530
    # # 0.5
531
    # logistic2_offset_p(1.,  [1., 2., 1.,  2., 2., 1.,  1.])
532
    # dlogistic(1., 1., 2., 1.)
533
    # # 0.5
534
    # dlogistic_offset(1., 1., 2., 1., 1.)
535
    # # 0.5
536
    # dlogistic2_offset(1.,  1., 2., 1.,  2., 2., 1.,  1.)
537
    # # -0.5
538
    # print(np.around(d2logistic(1., 1., 2., 2.),4))
539
    # # 0.3199
540
    # print(np.around(d2logistic_offset(1., 1., 2., 2., 1.),4))
541
    # # 0.3199
542
    # print(np.around(d2logistic2_offset(1., 1., 2., 2.,  2., 2., 2.,  1.),4))
543
    # # -0.3199
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc