Skip to content
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The data formats, examples, and available web service interfaces will all change

| Schema version | Java | SPIDAcalc | SPIDAstudio |
|----------------------------------------------------------------------------------|------|-------------------------|-------------|
| [12.0.1](https://github.com/spidasoftware/schema/releases/tag/v12.0.1) | 11+ | SPIDAcalc 25.0.0 | |
| [11.0.3](https://github.com/spidasoftware/schema/releases/tag/v11.0.3) | 11+ | SPIDAcalc 24.1.1 - 24.1.2 | |
| [11.0.2](https://github.com/spidasoftware/schema/releases/tag/v11.0.2) | 11+ | SPIDAcalc 24.1.0 | |
| [10.0.1](https://github.com/spidasoftware/schema/releases/tag/v10.0.1) | 11+ | SPIDAcalc 24.0.0 | |
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ apply plugin: 'com.spidasoftware.releaseNotes'
apply plugin: 'application'

group = 'com.spidasoftware'
version = '12.0.2' // If you're changing the major version also change the currentVersion in ConverterUtils.
version = '13.0.0-SNAPSHOT' // If you're changing the major version also change the currentVersion in ConverterUtils.

def schemaReleaseVersion = System.getenv("SCHEMA_RELEASE_VERSION")
if(schemaReleaseVersion){
Expand Down
7 changes: 5 additions & 2 deletions resources/schema/spidacalc/calc/design.schema
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@
"analysisCaseName": {
"type": "string"
},
"structureHash": {
"structureGroupHash": {
"type": "string"
},
"neighborStructuresIncluded": {
"type": "boolean"
}
},
"required": [
"jobId", "analysisCaseName", "structureHash"
"jobId", "analysisCaseName", "structureGroupHash", "neighborStructuresIncluded"
]
}
},
Expand Down
57 changes: 57 additions & 0 deletions resources/schema/spidacalc/calc/structure_group.schema
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"type": "object",
"id": "#/spidacalc/calc/structure_group.schema",
"description": "A mapping of structures to analyze",
"required": [
"primaryStructureId",
"primaryStructure",
"neighbors",
"spanningWireConnections"
],
"properties": {
"primaryStructureId": {
"type": "string",
"description": "The ID of the primary structures parent"
},
"primaryStructure": {
"description": "The primary structure to analyze",
"$ref": "../../spidacalc/calc/structure.schema"
},
"neighbors": {
"description": "List of neighbor structures to include in analysis finite model",
"type": "array",
"items": {
"$ref": "../../spidacalc/calc/structure.schema"
}
},
"spanningWireConnections": {
"description": "Attach height of the guy attach point.",
"type": "array",
"items": {
"description": "A mapping of (sourceStructureId, sourceWireId) -> (targetStructureId, targetWireId) for spanning wire connections",
"type": "object",
"required": [
"sourceStructureId",
"sourceWireId",
"targetStructureId",
"targetWireId"
],
"properties": {
"sourceStructureId": {
"type": "string"
},
"sourceWireId": {
"type": "string"
},
"targetStructureId": {
"type": "string"
},
"targetWireId": {
"type": "string"
}
}
}
}
},
"additionalProperties": false
}
8 changes: 4 additions & 4 deletions resources/schema/spidacalc/cee/analysis.schema
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "SPIDA CEE analysis object. The analysis objects are validated by the specific version of the engine that specified.",
"type": "object",
"required": [
"structure",
"structureGroup",
"analysisCase",
"clientData"
],
Expand All @@ -23,9 +23,9 @@
{"$ref": "../../spidacalc/client/strength_case.schema"}
]
},
"structure": {
"description": "The structure to be analyzed.",
"$ref": "../../spidacalc/calc/structure.schema"
"structureGroup": {
"description": "The structure group to be analyzed. Includes primary structure and optional neighbor structures.",
"$ref": "../../spidacalc/calc/structure_group.schema"
},
"clientData": {
"description": "The engineering data to be used to fill in the references on the structure.",
Expand Down
3 changes: 3 additions & 0 deletions resources/schema/spidacalc/client/load_case.schema
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
"ALL"
]
},
"includeNeighborStructures": {
"type": "boolean"
},
"analyzeGroundLineOnly": {
"type": "boolean"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 Bentley Systems, Incorporated. All rights reserved.
* Copyright (c) 2026 Bentley Systems, Incorporated. All rights reserved.
*/
package com.spidasoftware.schema.conversion.changeset

Expand All @@ -16,13 +16,14 @@ import com.spidasoftware.schema.conversion.changeset.v9.*
import com.spidasoftware.schema.conversion.changeset.v10.*
import com.spidasoftware.schema.conversion.changeset.v11.*
import com.spidasoftware.schema.conversion.changeset.v12.*
import com.spidasoftware.schema.conversion.changeset.v13.*
import groovy.util.logging.Slf4j
import org.apache.commons.lang3.StringUtils

@Slf4j
class ConverterUtils {

static final int currentVersion = 12
static final int currentVersion = 13

static {
addCalcConverter(new CalcProjectConverter())
Expand Down Expand Up @@ -89,6 +90,7 @@ class ConverterUtils {
converter.addChangeSet(12, new ComponentBraceChangeset())
converter.addChangeSet(12, new SidedPoleChangeset())
converter.addChangeSet(12, new CSAMaxWindLoadFactorsChangeSet())
converter.addChangeSet(13, new LeadAnalysisChangeSet())
// add calc changesets above here

converter.setCurrentVersion(currentVersion)
Expand Down Expand Up @@ -118,6 +120,7 @@ class ConverterUtils {
converter.addChangeSet(12, new ComponentBraceChangeset())
converter.addChangeSet(12, new SidedPoleChangeset())
converter.addChangeSet(12, new CSAMaxWindLoadFactorsChangeSet())
converter.addChangeSet(13, new LeadAnalysisChangeSet())
// add client data changesets above here

converter.setCurrentVersion(currentVersion)
Expand Down Expand Up @@ -148,6 +151,7 @@ class ConverterUtils {
converter.addChangeSet(12, new ComponentBraceChangeset())
converter.addChangeSet(12, new SidedPoleChangeset())
converter.addChangeSet(12, new CSAMaxWindLoadFactorsChangeSet())
converter.addChangeSet(13, new LeadAnalysisChangeSet())
// add result changesets above here

converter.setCurrentVersion(currentVersion)
Expand Down Expand Up @@ -185,6 +189,8 @@ class ConverterUtils {
return null
}
switch (engineVersion) {
case 26.0:
return 13
case 25.0:
return 12
case 24.1:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2026 Bentley Systems, Incorporated. All rights reserved.
*/
package com.spidasoftware.schema.conversion.changeset.v13

import com.spidasoftware.schema.conversion.changeset.ConversionException
import com.spidasoftware.schema.conversion.changeset.client.AbstractClientDataChangeSet
import groovy.transform.CompileStatic

@CompileStatic
class LeadAnalysisChangeSet extends AbstractClientDataChangeSet {

@Override
boolean applyToClientData(Map clientDataJSON) throws ConversionException {
// do nothing
return false
}

@Override
boolean revertClientData(Map clientDataJSON) throws ConversionException {
boolean changed = false
clientDataJSON.analysisCases?.each { Map analysisCase ->
changed |= (analysisCase.remove("includeNeighborStructures") != null)
}
return changed
}

@Override
void revertProject(Map projectJSON) throws ConversionException {
super.revertProject(projectJSON)
projectJSON.defaultLoadCases?.each { Map loadCase ->
loadCase.remove("includeNeighborStructures")
}
}

@Override
void revertDesign(Map designJSON) throws ConversionException {
super.revertDesign(designJSON)
designJSON.analysis?.each { Map analysis ->
Map analysisCase = analysis.analysisCaseDetails as Map
analysisCase?.remove("includeNeighborStructures")
}
designJSON.remove("pendingAnalysis")
}

@Override
boolean revertResults(Map resultsJSON) throws ConversionException {
boolean changed = super.revertResults(resultsJSON)
resultsJSON.results?.each { Map result ->
Map analysisCase = result.analysisCaseDetails as Map
if (analysisCase) {
changed |= (analysisCase.remove("includeNeighborStructures") != null)
}
}
return changed
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Bentley Systems, Incorporated. All rights reserved.
* Copyright (c) 2026 Bentley Systems, Incorporated. All rights reserved.
*/
package com.spidasoftware.schema.conversion.changeset

Expand Down Expand Up @@ -60,7 +60,7 @@ class ConverterUtilsSpec extends Specification {

def "test getPossibleVersionsNewestToOldest"() {
expect:
ConverterUtils.getPossibleVersionsNewestToOldest() == [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2] as LinkedHashSet
ConverterUtils.getPossibleVersionsNewestToOldest() == [13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2] as LinkedHashSet
}

def "pole-lean validation"() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2026 Bentley Systems, Incorporated. All rights reserved.
*/
package com.spidasoftware.schema.conversion.changeset.v13

import groovy.json.JsonSlurper
import spock.lang.Specification

class LeadAnalysisChangeSetTest extends Specification {

static LeadAnalysisChangeSet changeSet

def setupSpec() {
changeSet = new LeadAnalysisChangeSet()
}

def "revert client data"() {
setup:
InputStream stream = LeadAnalysisChangeSetTest.getResourceAsStream("/conversions/v13/leadAnalysis-v13-project.json")
Map json = new JsonSlurper().parse(stream) as Map
stream.close()
expect:
json.clientData.analysisCases[0].includeNeighborStructures == false
json.clientData.analysisCases[1].includeNeighborStructures == true
when:
boolean reverted = changeSet.revertClientData(json.clientData as Map)
then:
reverted
json.clientData.analysisCases[0].includeNeighborStructures == null
json.clientData.analysisCases[1].includeNeighborStructures == null
}

def "revert project"() {
setup:
InputStream stream = LeadAnalysisChangeSetTest.getResourceAsStream("/conversions/v13/leadAnalysis-v13-project.json")
Map json = new JsonSlurper().parse(stream) as Map
stream.close()
expect:
json.clientData.analysisCases[0].includeNeighborStructures == false
json.clientData.analysisCases[1].includeNeighborStructures == true
json.defaultLoadCases[0].includeNeighborStructures == false
json.defaultLoadCases[1].includeNeighborStructures == true
json.leads[0].locations[0].designs[0].analysis[0].analysisCaseDetails.includeNeighborStructures == false
json.leads[0].locations[0].designs[0].analysis[1].analysisCaseDetails.includeNeighborStructures == true
json.leads[0].locations[0].designs[0].pendingAnalysis.size() == 1
when:
changeSet.revertProject(json)
then:
json.clientData.analysisCases[0].includeNeighborStructures == null
json.clientData.analysisCases[1].includeNeighborStructures == null
json.defaultLoadCases[0].includeNeighborStructures == null
json.defaultLoadCases[1].includeNeighborStructures == null
json.leads[0].locations[0].designs[0].analysis[0].analysisCaseDetails.includeNeighborStructures == null
json.leads[0].locations[0].designs[0].analysis[1].analysisCaseDetails.includeNeighborStructures == null
json.leads[0].locations[0].designs[0].pendingAnalysis == null
}

def "revert results"() {
setup:
InputStream stream = LeadAnalysisChangeSetTest.getResourceAsStream("/conversions/v13/leadAnalysis-v13-results.json")
Map json = new JsonSlurper().parse(stream) as Map
stream.close()
expect:
json.clientData.analysisCases[0].includeNeighborStructures == false
json.clientData.analysisCases[1].includeNeighborStructures == true
json.results[0].analysisCaseDetails.includeNeighborStructures == false
json.results[1].analysisCaseDetails.includeNeighborStructures == true
when:
boolean reverted = changeSet.revertResults(json)
then:
reverted
json.clientData.analysisCases[0].includeNeighborStructures == null
json.clientData.analysisCases[1].includeNeighborStructures == null
json.results[0].analysisCaseDetails.includeNeighborStructures == null
json.results[1].analysisCaseDetails.includeNeighborStructures == null
}
}
Loading