pvperfsolar performance modeling

Reference

Guide

Scene JSON for agents

How to write a scene: the conventions, a recipe, converting a layout, and every rejection with its fix

What it is

A scene is a JSON section of the run request that places every rack, tracker and shading object in 3D. This page is the path from a layout to a scene that validates and runs, written for a program or an agent producing the JSON. The field pages (scene, scene.types, scene.placements, scene.objects, scene.outlines, scene.frame) hold each key's detail.

The frame

Every scene uses one convention: x east, y north, z up, azimuths in degrees clockwise from true north, and lengths in one unit of your choice. The frame block is optional; when sent it must read exactly:

"frame": {"axes": {"x": "east", "y": "north", "z": "up"},
          "azimuth_zero": "true_north", "azimuth_direction": "clockwise",
          "lengths": "unitless"}

The recipe

  1. Pick one length unit, metres or feet, and use it for every length in the scene.
  2. Put the origin at or near the site: x east, y north, z up, azimuths in degrees clockwise from true north. The frame block states this and cannot say anything else.
  3. Write one device type per rack or tracker size: kind (gft fixed rack or sat single-axis tracker), length along the row or axis, width across it (the collector width), modules and strings on one device.
  4. Write one placement per device: the type, the centre x, y, z (a tracker's axis midpoint at hub height, a rack's plane centre), azimuth_deg, tilt_deg and, for a rack, roll_deg.
  5. Add the objects that cast shade: a building as one or more prism (a base polygon with a height per vertex), a wall or a tree_line (a polyline with a height per vertex; a tree line lets light through), a cylinder for a tree, a tank or a pole.
  6. POST /api/scene/validate with the scene as the body. Fix each rejection (table below) and read the warnings; the response counts the placements, objects, modules and orientation bins.
  7. Set the array section for the scene: array.inter_row_shading true for rows on the ground or on a flat roof, false for modules flush on a pitched roof; the tracker operation (rotation limits, backtracking, stow) in array when the scene places trackers, which rooftop racking refuses; the stringing and the inverter sized for the scene's modules (the run takes the nameplate from them, not from the scene). A bifacial section gives every orientation group its own rear side; leave it out on a roof and on east-west racking.
  8. POST /api/run with the scene in scene. Read summary.warnings (the pitch check, the module totals) and summary.scene (the bins, the origin).
  9. POST /api/scene/day?date=MM-DD with the same request returns one day solved: the sun, each bin's tracker rotation, the trackers' state (tracking: tracking, backtracking, flat (irradiance-optimised), best angle (irradiance-optimised) or stow, read from the first tracker bin) and each table's beam shaded fraction per timestep.

One setup per run

A run is one plant: one module, one inverter design and one racking geometry. For several roof planes, products or row spacings, make one run each and add the results.

Starting from an example

GET /api/scene-examples lists five maintained scenes with the array settings each assumes (array_patch, a shallow merge into array) and notes; GET /api/scene-examples/{id} returns the scene body.

Example What it shows
residential A gable-roof house with eight one-module placements flush on the south roof, a neighbouring house (two sloped prisms each) and two trees as cylinders; row-to-row shading off
commercial A flat roof with three arrays of 15° rows in two row lengths, an HVAC unit splitting the middle row and rooftop units along the edges; row-to-row shading on
ground_fixed 515 fixed racks in three sizes at 25° on rolling ground, each centre 1.5 above it, in three blocks with irregular edges
ground_tracker 324 single-axis trackers in two lengths on rolling ground, each axis following the ground (tilted where it falls), in four blocks split by roads
east_west 42 east-west ridges of 40 modules (1,680 modules) with faces at 10° on flat ground, 5.4 apart, in a block with one ragged edge, a two-storey building to the south-east and a tree to the west; array.track_mode ewf, row-to-row shading on

Start from the closest one: keep the frame block, replace the types, placements and objects, and merge its array_patch.

Placing devices from your own layout

A PVsyst variant. POST /api/parse-scene with the .VCx file (multipart file) returns the scene, an array_patch carrying the tracker operation and the import notes, which list the shapes it could not read. Merge the patch into array before running.

A rectangle per device (CAD drawing, GIS layer, KML polygon). For each device's rectangle in plan:

Longitude and latitude (KML, KMZ, GeoJSON). Convert each point to east and north offsets from a reference point near the site (λ₀, φ₀) in metres: x = (λ − λ₀) · (π/180) · R · cos φ₀ and y = (φ − φ₀) · (π/180) · R, with R = 6 371 000 m. Within a few kilometres of the reference point the error is below 0.2 % of the distance. KML altitudes are absolute or relative to the ground (altitudeMode): a relative altitude is a height above the ground, so add the ground elevation under the point on sloping ground. Bearings from these offsets are true bearings.

Projected coordinates (a CAD drawing in UTM or a state plane grid). Subtract the site's projected coordinates so the numbers stay small, and keep the drawing's unit. Grid north is not true north: a bearing measured on the grid is a true bearing plus the grid convergence γ, the angle from true north to grid north (positive when grid north lies east of true north; for UTM, γ ≈ (λ − λ₀) · sin φ with λ₀ the zone's central meridian). Rotate each offset (x, y) to (x cos γ + y sin γ, −x sin γ + y cos γ), and add γ to each bearing read from the grid. At 1° of convergence, an unrotated layout faces every device 1° off.

The georeference. origin (latitude, longitude, elevation) records the reference point you used; the run rejects one more than 10 km from the site. The sun position, the weather and the elevation come from site alone, so set site to the system's location either way.

Rejections and their fixes

Rejections are 422 problems (application/problem+json) whose field names the offending key (types.0.kind from the validate endpoint, scene.types.0.kind from a run) and whose errors list every failure.

Message (start) Fix
version: Input should be 2 Send "version": 2; earlier scene formats are not accepted.
frame.…: Input should be … Send the frame block exactly as above, or leave it out.
…: Extra inputs are not permitted Remove the key. A unit in a key name (length_m) is refused: lengths are unitless.
scene.length_unit: the scene is unitless Delete it; every length is in one unit of your choice.
scene.archetype: archetype was removed Delete archetype; mix gft and sat types freely. For a roof, set array.inter_row_shading to false.
scene.types[i].kind: roof types were removed (also .roof) Model a roof array as a gft type placed on the roof plane (tilt = the roof pitch).
scene.….clearance: clearance was removed Delete it: z places the device.
scene.types[i].sat: the sat block was removed Delete it; set the rotation limits, backtracking and stow in array.
types: List should have at least 1 item (or at most 10) Give 1 to 10 device types.
types.i.kind: Input should be 'gft' or 'sat' Use gft for a fixed rack (a roof array too) or sat for a single-axis tracker.
scene.types[i].id: duplicate id (also placements, objects) Make the ids unique, or leave placement ids out (they default to p1, p2, …).
scene.placements[i].type: unknown type Name a type id that exists in types.
scene.placements[i].tilt_deg: must be within [0, 90] (a rack) or [-45, 45] (a tracker axis); …azimuth_deg or …roll_deg: Input should be less than or equal to … Racks tilt 0–90°, tracker axes −45–45°; azimuths 0–360°; rolls −45–45°.
scene.….x: must be finite Replace NaN or infinite numbers.
…width: Input should be greater than 0 (also length, a cylinder's height) A type's length and width and a cylinder's height are positive; modules and strings are at least 1.
objects.i: Input tag '…' found using 'kind' does not match Use prism, wall, tree_line or cylinder.
…vertices: List should have at least 3 items A prism or an outline needs 3 vertices, a wall or tree line 2.
…vertices.k: List should have at least 4 items Object vertices are [x, y, z, h]: a base point and the height above it. Outline vertices are [x, y, z].
scene.objects[i].vertices: h must be positive on at least one vertex Give the object a height.
scene.objects[i].radius: give exactly one of radius or diameter Keep one of the two.
objects.i.wall.transmittance: Extra inputs are not permitted A wall is opaque; use a tree_line for a screen that lets light through.
scene: sat (tracker) types are not available with rooftop racking Set array.track_mode to fixed or single_axis, or make the types gft.
scene: ewf types cannot share a scene with gft or sat types Put the east-west ridges in a scene of their own.
scene: ewf types need array.track_mode ewf, and ewf racking needs ewf types Set array.track_mode to ewf for ewf types; for gft and sat types use fixed, single_axis or rooftop racking.
scene.types[i].modules: must be even for an ewf type (half on each face) (also strings) Count both faces of the ridge: an even number.
scene.origin: is N km from the site Move origin within 10 km of site, or leave it out.
scene.bins: N orientation bins exceed the limit of 400 Round the tilts and azimuths: placements within 1° of tilt and 2.5° of azimuth share a bin.

Warnings

Warnings do not stop the run. POST /api/scene/validate returns the scene's own; POST /api/run adds the ones that need the array section to summary.warnings.

Warning What to check
types T: no placement uses it Delete the type or place it.
placements[i] P: roll_deg is ignored on a sat type A tracker rolls about its own axis; delete the roll.
objects[i] O: non-convex prism, shaded as its convex hull Split an L-shaped or U-shaped building into convex prisms.
placements A and B overlap in plan (N pairs in all) Two devices occupy the same ground: a duplicated row or a wrong centre. An overlap still runs and shades twice.
pitch from the placements differs from width / GCR by up to N % The row-to-row model uses array.gcr; set it to width / pitch of your layout.
ridge spacing from the placements differs from 2 × width × cos(tilt) / GCR by up to N % On east-west racking the row-to-row model reads array.gcr as the two faces' footprint over the ridge spacing; set it to 2 × width × cos(tilt) / spacing of your layout.
placements[i] P: roll_deg is ignored on an ewf type A ridge's faces take the placement's tilt only; delete the roll.
scene tables carry N modules; the racking section declares M The scene's module counts weight the blend; the stringing and inverter set the nameplate. Size them to the scene's total.

Limits

Run time

References

  1. ISO 19111:2019, Geographic information — referencing by coordinates
  2. Snyder 1987, Map Projections: A Working Manual, U.S. Geological Survey Professional Paper 1395
  3. Open Geospatial Consortium 2008, OGC KML, version 2.2.0 (OGC 07-147r2)