Skip to main content
Glama

wind_model_simple

Calculate wind speeds at multiple altitudes with logarithmic or power law wind models. Provide surface wind data and roughness length to get wind profile.

Instructions

Calculate wind speeds at different altitudes using logarithmic or power law models.

Args: altitudes_m: List of altitudes in meters surface_wind_speed_ms: Wind speed at 10m reference height in m/s surface_wind_direction_deg: Wind direction at surface in degrees (0=North, 90=East) model_type: Wind model type ('logarithmic' or 'power_law') roughness_length_m: Surface roughness length in meters

Returns: Formatted string with wind profile data at each requested altitude.

Raises: No exceptions are raised directly; errors are returned as formatted strings.

Note: The logarithmic wind profile (Ref: Stull, "Meteorology for Scientists and Engineers", 2000) models wind speed as: U(z) = (u* / kappa) * ln(z / z0) where u* is friction velocity, kappa ~0.4 is the von Karman constant, and z0 is the aerodynamic roughness length.

The **power-law wind profile** (empirical approximation) models wind as:
    U(z) = U_ref * (z / z_ref) ^ alpha
where alpha (Hellmann exponent) depends on terrain roughness, typically
~0.14 for open terrain and ~0.40 for urban areas.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
altitudes_mYes
surface_wind_speed_msNo
surface_wind_direction_degNo
model_typeNologarithmic
roughness_length_mNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Main MCP tool handler for wind_model_simple. Takes altitudes, wind speed/direction, model type, and roughness length. Delegates to the integration layer and formats the result as a human-readable string with JSON output.
    def wind_model_simple(
        altitudes_m: list[float],
        surface_wind_speed_ms: float = 5.0,
        surface_wind_direction_deg: float = 270.0,
        model_type: Literal["logarithmic", "power_law"] = "logarithmic",
        roughness_length_m: float = 0.03,
    ) -> str:
        """Calculate wind speeds at different altitudes using logarithmic or power law models.
    
        Args:
            altitudes_m: List of altitudes in meters
            surface_wind_speed_ms: Wind speed at 10m reference height in m/s
            surface_wind_direction_deg: Wind direction at surface in degrees (0=North, 90=East)
            model_type: Wind model type ('logarithmic' or 'power_law')
            roughness_length_m: Surface roughness length in meters
    
        Returns:
            Formatted string with wind profile data at each requested altitude.
    
        Raises:
            No exceptions are raised directly; errors are returned as formatted strings.
    
        Note:
            The **logarithmic wind profile** (Ref: Stull, "Meteorology for Scientists
            and Engineers", 2000) models wind speed as:
                U(z) = (u* / kappa) * ln(z / z0)
            where u* is friction velocity, kappa ~0.4 is the von Karman constant,
            and z0 is the aerodynamic roughness length.
    
            The **power-law wind profile** (empirical approximation) models wind as:
                U(z) = U_ref * (z / z_ref) ^ alpha
            where alpha (Hellmann exponent) depends on terrain roughness, typically
            ~0.14 for open terrain and ~0.40 for urban areas.
        """
        try:
            from ..integrations.atmosphere import wind_model_simple as _wind_model
    
            # Call integration function with correct argument mapping.
            # The integration layer implements the logarithmic or power-law profile
            # equations described above, using 10 m as the standard reference height.
            wind_profile = _wind_model(
                altitudes_m,
                surface_wind_speed_ms,
                0.0,  # surface_altitude_m
                model_type,
                roughness_length_m,
            )
    
            # Format response
            result_lines = [f"Wind Profile ({model_type} model)", "=" * 50]
            result_lines.extend(
                [
                    f"Surface Reference: {surface_wind_speed_ms:.1f} m/s @ {surface_wind_direction_deg:.0f}° (10m height)",
                    f"Roughness Length: {roughness_length_m:.3f} m",
                    "",
                    f"{'Alt (m)':>8} {'Speed (m/s)':>12} {'Dir (deg)':>10}",
                ]
            )
            result_lines.append("-" * 40)
    
            for point in wind_profile:
                # Use correct attribute name (wind_speed_mps not wind_speed_ms)
                # Direction is assumed constant (from surface_wind_direction_deg)
                direction = (
                    point.wind_direction_deg
                    if point.wind_direction_deg is not None
                    else surface_wind_direction_deg
                )
                result_lines.append(
                    f"{point.altitude_m:8.0f} {point.wind_speed_mps:12.1f} {direction:10.0f}"
                )
    
            # Add JSON data with direction filled in
            json_output = [
                {
                    "altitude_m": p.altitude_m,
                    "wind_speed_mps": p.wind_speed_mps,
                    "wind_direction_deg": (
                        p.wind_direction_deg
                        if p.wind_direction_deg is not None
                        else surface_wind_direction_deg
                    ),
                }
                for p in wind_profile
            ]
            json_data = json.dumps(json_output, indent=2)
            result_lines.extend(["", "JSON Data:", json_data])
    
            return "\n".join(result_lines)
    
        except ImportError:
            return "Wind modeling not available - atmospheric integration required"
        except Exception as e:
            logger.error(f"Wind model error: {str(e)}", exc_info=True)
            return f"Wind model error: {str(e)}"
  • WindPoint data model (BaseModel) used as the return type of the integration function. Fields: altitude_m, wind_speed_mps, wind_direction_deg.
    class WindPoint(BaseModel):
        """Single wind profile point."""
    
        altitude_m: float = Field(..., description="Altitude in meters")
        wind_speed_mps: float = Field(..., description="Wind speed in m/s")
        wind_direction_deg: float | None = Field(
            None, description="Wind direction in degrees"
        )
  • Core integration implementation of wind_model_simple. Computes wind speeds using logarithmic or power-law profiles with NumPy vectorization. Returns list of WindPoint objects.
    def wind_model_simple(
        altitudes_m: list[float],
        surface_wind_mps: float,
        surface_altitude_m: float = 0.0,
        model: str = "logarithmic",
        roughness_length_m: float = 0.1,
        reference_height_m: float = 10.0,
    ) -> list[WindPoint]:
        """Simple wind profile models for low-altitude boundary-layer studies.
    
        Two models are supported:
    
        **Logarithmic** (neutral atmospheric stability)::
    
            U(z) = U_ref * ln(z / z0) / ln(z_ref / z0)
    
        where z0 is the aerodynamic roughness length and z_ref is the
        measurement reference height.
    
        **Power law**::
    
            U(z) = U_ref * (z / z_ref) ^ alpha
    
        where alpha is the wind shear exponent (default 0.143 for open
        terrain, per Davenport).
    
        Args:
            altitudes_m: Altitude points for wind calculation (m ASL).
            surface_wind_mps: Wind speed at reference height (m/s).
            surface_altitude_m: Ground elevation (m ASL).
            model: ``"logarithmic"`` or ``"power"`` law.
            roughness_length_m: Aerodynamic roughness length z0 (m).
                Typical values: 0.0002 (water), 0.03 (grass), 0.1 (crops),
                1.0 (suburban).
            reference_height_m: Height of surface wind measurement (m AGL).
    
        Returns:
            List of wind profile points with wind speed at each altitude.
        """
        if model not in ["logarithmic", "power"]:
            raise ValueError(f"Unknown wind model: {model}. Use 'logarithmic' or 'power'")
    
        if model == "logarithmic" and roughness_length_m <= 0:
            raise ValueError("Roughness length must be positive")
    
        # Convert to NumPy array for vectorized operations
        altitudes = np.asarray(altitudes_m, dtype=np.float64)
        heights_agl = altitudes - surface_altitude_m
    
        # Initialize wind speeds
        wind_speeds = np.zeros_like(altitudes)
    
        # Below ground mask
        below_ground = heights_agl < 0
        wind_speeds[below_ground] = 0.0
    
        # Below reference height - linear interpolation
        below_ref = (heights_agl >= 0) & (heights_agl < reference_height_m)
        wind_speeds[below_ref] = (
            surface_wind_mps * heights_agl[below_ref] / reference_height_m
        )
    
        # Above reference height
        above_ref = heights_agl >= reference_height_m
    
        if model == "logarithmic":
            # Logarithmic wind profile (neutral stability):
            # U(z) = U_ref * ln(z/z0) / ln(z_ref/z0)
            log_ratio_ref = np.log(reference_height_m / roughness_length_m)
            wind_speeds[above_ref] = surface_wind_mps * (
                np.log(heights_agl[above_ref] / roughness_length_m) / log_ratio_ref
            )
        else:  # power law
            # Power law: U(z) = U_ref * (z/z_ref)^alpha
            # alpha = 0.143 (1/7 power law, Davenport, open terrain)
            alpha = 0.143
            wind_speeds[above_ref] = (
                surface_wind_mps * (heights_agl[above_ref] / reference_height_m) ** alpha
            )
    
        # Ensure non-negative
        wind_speeds = np.maximum(wind_speeds, 0.0)
    
        # Convert to output format
        results = []
        alt_numpy = to_numpy(altitudes)
        ws_numpy = to_numpy(wind_speeds)
    
        for i, altitude in enumerate(alt_numpy):
            results.append(
                WindPoint(
                    altitude_m=float(altitude),
                    wind_speed_mps=float(ws_numpy[i]),
                )
            )
    
        return results
  • Registration of wind_model_simple as an mcp.tool in the FastMCP server.
    mcp.tool(wind_model_simple)
  • ToolReference entry for wind_model_simple used by the AI agent tool selection system. Defines parameters and example calls.
    ToolReference(
        name="wind_model_simple",
        description="Calculate wind profiles at various altitudes",
        parameters={
            "altitudes_m": "List[float] - List of altitudes in meters",
            "surface_wind_mps": "float - Surface wind speed in m/s",
            "model": "Literal['logarithmic', 'power_law'] - Wind profile model (default 'logarithmic')",
            "surface_roughness_m": "float - Surface roughness in meters (default 0.1)",
        },
        examples=[
            "wind_model_simple([0, 100, 500, 1000], 10.0)",
            'wind_model_simple([0, 200, 1000, 3000], 15.0, "power_law", 0.05)',
        ],
    ),
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Details the two models with formulas and references, and states that errors are returned as formatted strings (no exceptions). With no annotations, this covers key behavioral aspects adequately.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with sections for args, returns, raises, and notes. Contains necessary formulas, but could be trimmed slightly without losing clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, parameters, error handling, and references. With an output schema present (per context), not needing full return description. Lacks examples or typical usage scenarios.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 0% schema description coverage, the description independently explains all 5 parameters with units and context (e.g., 'Wind speed at 10m reference height', model_type enum explained).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it calculates wind speeds at different altitudes using specific models (logarithmic or power law). Distinguishes from siblings like get_atmosphere_profile by focusing on wind only.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternative tools like get_atmosphere_profile or density_altitude_calculator. Lacks 'when not to use' or explicit context for selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cheesejaguar/aerospace-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server