| Conditions | 25 |
| Total Lines | 137 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 5 | ||
| Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like get_layer() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | # Copyright (c) 2008-2017 MetPy Developers. |
||
| 337 | @exporter.export |
||
| 338 | @check_units('[pressure]') |
||
| 339 | def get_layer(p, *args, heights=None, bottom=None, depth=100 * units.hPa, interpolate=True): |
||
| 340 | r"""Return an atmospheric layer from upper air data with the requested bottom and depth. |
||
| 341 | |||
| 342 | This function will subset an upper air dataset to contain only the specified layer. The |
||
| 343 | bottom of the layer can be specified with a pressure or height above the surface |
||
| 344 | pressure. The bottom defaults to the surface pressure. The depth of the layer can be |
||
| 345 | specified in terms of pressure or height above the bottom of the layer. If the top and |
||
| 346 | bottom of the layer are not in the data, they are interpolated by default. |
||
| 347 | |||
| 348 | Parameters |
||
| 349 | ---------- |
||
| 350 | p : array-like |
||
| 351 | Atmospheric pressure profile |
||
| 352 | datavar : array-like |
||
| 353 | Atmospheric variable measured at the given pressures |
||
| 354 | bottom : `pint.Quantity` |
||
| 355 | The bottom of the layer as a pressure or height above the surface pressure |
||
| 356 | depth : `pint.Quantity` |
||
| 357 | The thickness of the layer as a pressure or height above the bottom of the layer |
||
| 358 | interpolate : bool |
||
| 359 | Interpolate the top and bottom points if they are not in the given data |
||
| 360 | |||
| 361 | Returns |
||
| 362 | ------- |
||
| 363 | `pint.Quantity, pint.Quantity` |
||
| 364 | The pressure and data variable of the layer |
||
| 365 | |||
| 366 | """ |
||
| 367 | # Make sure pressure and datavar are the same length |
||
| 368 | for datavar in args: |
||
| 369 | if len(p) != len(datavar): |
||
| 370 | raise ValueError('Pressure and data variable must have the same length.') |
||
| 371 | |||
| 372 | # Bottom of layer calculations |
||
| 373 | |||
| 374 | # If no bottom is specified, use the first pressure value |
||
| 375 | if not bottom: |
||
| 376 | bottom_pressure = p[0] |
||
| 377 | if heights is not None: |
||
| 378 | bottom_height = heights[0] |
||
| 379 | else: |
||
| 380 | bottom_height = pressure_to_height_std(bottom_pressure) |
||
| 381 | |||
| 382 | # If the bottom pressure is specified |
||
| 383 | if bottom: |
||
| 384 | # in pressure units, assign it |
||
| 385 | if bottom.dimensionality == {'[length]': -1.0, '[mass]': 1.0, '[time]': -2.0}: |
||
| 386 | bottom_pressure = bottom |
||
| 387 | if heights is not None: |
||
| 388 | bottom_height = log_interp(bottom_pressure, p, heights) |
||
| 389 | else: |
||
| 390 | bottom_height = pressure_to_height_std(bottom_pressure) |
||
| 391 | # in height units |
||
| 392 | if bottom.dimensionality == {'[length]': 1.0}: |
||
| 393 | bottom_height = bottom |
||
| 394 | if heights is not None: |
||
| 395 | bottom_pressure = np.interp(np.array([bottom_height.m]), heights, |
||
| 396 | p)[0] * p.units |
||
| 397 | else: |
||
| 398 | bottom_pressure = height_to_pressure_std(bottom_height) |
||
| 399 | |||
| 400 | # Top of layer calculations |
||
| 401 | |||
| 402 | # Depth is in pressure |
||
| 403 | if depth.dimensionality == {'[length]': -1.0, '[mass]': 1.0, '[time]': -2.0}: |
||
| 404 | top_pressure = bottom_pressure - depth |
||
| 405 | if heights is not None: |
||
| 406 | top_height = log_interp(top_pressure, p, heights) |
||
| 407 | else: |
||
| 408 | top_height = pressure_to_height_std(top_pressure) |
||
| 409 | |||
| 410 | # Depth is in height |
||
| 411 | if depth.dimensionality == {'[length]': 1.0}: |
||
| 412 | top_height = bottom_height + depth |
||
| 413 | if heights is not None: |
||
| 414 | top_pressure = np.interp(np.array([top_height.m]), heights, p)[0] * p.units |
||
| 415 | else: |
||
| 416 | top_pressure = height_to_pressure_std(top_height) |
||
| 417 | |||
| 418 | # Handle top or bottom values that are invalid |
||
| 419 | if bottom_pressure > p[0]: |
||
| 420 | raise ValueError( |
||
| 421 | 'Bottom of layer pressure is greater than the largest pressure in data.') |
||
| 422 | if top_pressure < p[-1]: |
||
| 423 | raise ValueError('Top of layer pressure is less than the lowest pressure in data.') |
||
| 424 | if bottom_pressure < top_pressure: |
||
| 425 | raise ValueError( |
||
| 426 | 'Pressure at the top of the layer is greater than that at the bottom.') |
||
| 427 | |||
| 428 | ret = [] # returned data variables in layer |
||
| 429 | |||
| 430 | # Ensure pressures are sorted in ascending order |
||
| 431 | sort_inds = np.argsort(p) |
||
| 432 | p = p[sort_inds] |
||
| 433 | |||
| 434 | # Mask based on top and bottom pressure |
||
| 435 | inds = (p <= bottom_pressure) & (p >= top_pressure) |
||
| 436 | p_interp = p[inds] |
||
| 437 | |||
| 438 | # Interpolate pressures at bounds if necessary and sort |
||
| 439 | if interpolate: |
||
| 440 | # If we don't have the bottom or top requested, append them |
||
| 441 | if top_pressure not in p_interp: |
||
| 442 | p_interp = np.sort(np.append(p_interp, top_pressure)) * p.units |
||
| 443 | if bottom_pressure not in p_interp: |
||
| 444 | p_interp = np.sort(np.append(p_interp, bottom_pressure)) * p.units |
||
| 445 | |||
| 446 | for datavar in args: |
||
| 447 | # Ensure that things are sorted in ascending order |
||
| 448 | datavar = datavar[sort_inds] |
||
| 449 | |||
| 450 | if interpolate: |
||
| 451 | # Interpolate for the possibly missing bottom/top values |
||
| 452 | datavar_interp = log_interp(p_interp, p, datavar) |
||
| 453 | datavar = datavar_interp |
||
| 454 | else: |
||
| 455 | datavar = datavar[inds] |
||
| 456 | |||
| 457 | ret.append(datavar[::-1]) |
||
| 458 | |||
| 459 | # If heights are given, return the height range as well as pressure range |
||
| 460 | if heights is not None: |
||
| 461 | heights_clipped = heights[((heights >= bottom_height) & (heights <= top_height))] |
||
| 462 | |||
| 463 | if bottom_height not in heights: |
||
| 464 | heights_clipped = np.sort(np.append(heights_clipped, |
||
| 465 | bottom_height)) * heights.units |
||
| 466 | if top_height not in heights: |
||
| 467 | heights_clipped = np.sort(np.append(heights_clipped, top_height)) * heights.units |
||
| 468 | |||
| 469 | ret.insert(0, heights_clipped) |
||
| 470 | |||
| 471 | ret.insert(0, p_interp[::-1]) |
||
| 472 | |||
| 473 | return ret |
||
| 474 |