Module:Model: Difference between revisions

From MaRDI portal
No edit summary
No edit summary
 
(146 intermediate revisions by 2 users not shown)
Line 5: Line 5:
local mw = require('mw')
local mw = require('mw')
local json = require("mw.text")  
local json = require("mw.text")  


-- Main table to hold all functions
-- Main table to hold all functions
local p = {}
local p = {}
-------------------------------- Local Functions -------------------------------
-- Utility: get all P31 values of an entity
local function getInstanceOf(qid)
    local e = mw.wikibase.getEntityObject(qid)
    local result = {}
    if not e or not e.claims or not e.claims["P31"] then
        return result
    end
    for _, claim in pairs(e.claims["P31"]) do
        local id = claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value.id
        if id then
            table.insert(result, id)
        end
    end
    return result
end
-------------------------------- Local Functions -------------------------------




Line 26: Line 48:
end
end
------------------------------- Helper Functions -------------------------------
------------------------------- Helper Functions -------------------------------
-- Function to get model types
function p.getModelTypes(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: used by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?ModelTypeLabel WHERE {
  entityId: p:P31 ?statement .
  ?statement ps:P31 ?ModelType .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?ModelTypeLabel
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
    end
local modelTypes = {}
    -- Get the number of model types
local totalModelTypes = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalModelTypes  do
    local item = jsonResults.results.bindings[index]
    if item and item.ModelTypeLabel and item.ModelTypeLabel.value then
        local label = item.ModelTypeLabel.value
        table.insert(modelTypes, label)
    end
end
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n|-\n| " .. table.concat(modelTypes, " || ") .. "\n|}"
return wikitextTable
end


-- Function to get Computational Tasks
-- Function to get Computational Tasks
Line 39: Line 109:
     -- P147: used by property id
     -- P147: used by property id
     -- P146: series ordinal property id
     -- P146: series ordinal property id
     --local sparqlQuery = [[
     local sparqlQuery = [[
--PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
-- SELECT ?URL ?Label ?Ordinal
SELECT ?URL ?Label (SAMPLE(?StatementOrdinal) AS ?Ordinal)
-- WHERE {
WHERE {
entityId: p:P147 ?statement.
?statement ps:P147 ?URL.
OPTIONAL { ?statement pq:P146 ?StatementOrdinal. }
?URL rdfs:label ?Label.
FILTER(LANG(?Label) = "en")
}
GROUP BY ?URL ?Label
ORDER BY
ASC(COALESCE(xsd:integer(?Ordinal), 999999))
ASC(?Label)
]]
 
-- local sparqlQuery = [[
-- PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
-- SELECT ?URL ?URLLabel ?nextURL ?nextURLLabel
-- WHERE {
-- entityId: p:P147 ?statement.
-- entityId: p:P147 ?statement.
-- ?statement ps:P147 ?URL.
-- ?statement ps:P147 ?URL.
-- OPTIONAL { ?statement pq:P146 ?Ordinal. }
-- OPTIONAL { ?statement pq:P146 ?Ordinal. }
-- ?URL rdfs:label ?Label.
-- OPTIONAL { ?statement pq:P581 ?nextURL. }
-- }
-- SERVICE wikibase:label {
-- ORDER BY ASC(xsd:integer(COALESCE(?Ordinal, 9999)))
-- bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
-- }
-- ORDER BY ASC(xsd:integer(COALESCE(?Ordinal, 9999)))
-- ]]
-- ]]
local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?URL ?URLLabel ?nextURL ?nextURLLabel
WHERE {
entityId: p:P147 ?statement.
?statement ps:P147 ?URL.
OPTIONAL { ?statement pq:P146 ?Ordinal. }
OPTIONAL { ?statement pq:P581 ?nextURL. }
SERVICE wikibase:label {
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
ORDER BY ASC(xsd:integer(COALESCE(?Ordinal, 9999)))
]]




Line 81: Line 154:
for index = 0, totalCompTasks  do
for index = 0, totalCompTasks  do
     local item = jsonResults.results.bindings[index]
     local item = jsonResults.results.bindings[index]
     if not item.URLLabel.value then
     if not item.Label.value then
         return "Error: Missing item.Label.value"
         return "Error: Missing item.Label.value"
     elseif not item.URL.value then
     elseif not item.URL.value then
         return "Error: Missing item.URL.value"
         return "Error: Missing item.URL.value"
     else
     else
         local label = item.URLLabel.value
         local label = item.Label.value
         local url = item.URL.value
         local url = item.URL.value
         local numericId = url:match("Q(%d+)")
         local numericId = url:match("Q(%d+)")
     local urlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. numericId
     local urlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. numericId
         local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
         local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
         --local ordinal = item.Ordinal and item.Ordinal.value or nil
         local ordinal = item.Ordinal and item.Ordinal.value or nil
--local prefix = ordinal and (ordinal .. ". ") or ""
local prefix = ordinal and (ordinal .. ". ") or ""
if item.nextURL then
table.insert(computationalTasks, "| " .. prefix .. labelWithUrl)
local nexturl = item.nextURL.value
-- if item.nextURL then
local nextnumericId = nexturl:match("Q(%d+)")
-- local nexturl = item.nextURL.value
local nextLabel = item.nextURLLabel.value
-- local nextnumericId = nexturl:match("Q(%d+)")
local nexturlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. nextnumericId
-- local nextLabel = item.nextURLLabel.value
local nextLabelWithUrl = string.format('[%s %s]', tostring(nexturlRendered), tostring(nextLabel))
-- local nexturlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. nextnumericId
table.insert(computationalTasks, "| " .. labelWithUrl .. " followed by " .. nextLabelWithUrl)
-- local nextLabelWithUrl = string.format('[%s %s]', tostring(nexturlRendered), tostring(nextLabel))
else
-- table.insert(computationalTasks, "| " .. labelWithUrl .. " followed by " .. nextLabelWithUrl)
table.insert(computationalTasks, "| " .. labelWithUrl)
-- else
end
-- table.insert(computationalTasks, "| " .. labelWithUrl)
-- end
     end
     end
end
end
Line 111: Line 185:


end
end


-- Function to get Formulations with Quantities
-- Function to get Formulations with Quantities
Line 128: Line 201:
     local sparqlQuery = [[
     local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?Formula ?defining_formulation ?IDFormula  
SELECT ?Formula ?defining_formulation ?IDFormula ?qualValueLabel ?qualValue
WHERE {
WHERE {
      entityId: wdt:P1560 ?IDFormula.
# full statement node for P1560
      ?IDFormula rdfs:label ?Formula.
entityId: p:P1560 ?statement .
      ?IDFormula wdt:P989 ?defining_formulation.
?statement ps:P1560 ?IDFormula .
FILTER(LANG(?qualValueLabel) = "en")
 
OPTIONAL {
    ?IDFormula rdfs:label ?Formula .
    FILTER(LANG(?Formula) = "en")
}
OPTIONAL { ?IDFormula wdt:P989 ?defining_formulation . }
 
# qualifiers on this statement
OPTIONAL {
    ?statement ?qualProp ?qualValue .
    FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))  # only qualifiers
    OPTIONAL {
    ?qualProp rdfs:label ?qualPropLabel .
    FILTER(LANG(?qualPropLabel) = "en")
    }
    OPTIONAL {
    ?qualValue rdfs:label ?qualValueLabel .
    FILTER(LANG(?qualValueLabel) = "en")
    }
}
}
}
    ]]
ORDER BY ?Formula
   
]]
 
-- Executing the SPARQL query and retrieving results in JSON format
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
local jsonResults = sparql.runQuery(sparqlQuery)
Line 141: Line 236:
-- Validate results
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return "\"No mathematical expressions found.\""
return "\"No mathematical expressions found.\""
     end
     end
--local resultTable = p.convertJsonToTable(jsonResults)
-- local resultTable = p.convertJsonToTable(jsonResults)
--return "<pre>" .. mw.text.nowiki(json.jsonEncode(resultTable)) .. "</pre>"
-- return "<pre>" .. mw.text.nowiki(json.jsonEncode(resultTable)) .. "</pre>"
     local jsonString = mw.text.jsonEncode(jsonResults)
     -- local jsonString = mw.text.jsonEncode(jsonResults)
     -- return "<pre>" .. mw.text.nowiki(jsonString) .. "</pre>"
     -- return "<pre>" .. mw.text.nowiki(jsonString) .. "</pre>"
    return p.extractDefiningFormulationsWithQuantities(jsonResults)
return p.extractDefiningFormulationsWithQuantities(jsonResults)


end
end


-- Function to extract Formulations with Quantities  
-- Function to extract Formulations with Quantities  
function p.extractDefiningFormulationsWithQuantities(jsonResults)
function p.extractDefiningFormulationsWithQuantities(jsonResults)
local frame = mw.getCurrentFrame()
local frame = mw.getCurrentFrame()
-- Table to store formulations
-- Table to store contained entities
     local formulations = {}
     local containedEntities = {}
     -- Table to store quantity symbol and name id  
     -- Table to store quantity symbol and name id  
     local quantitySymbolNameIdPairs = {}
     local quantitySymbolNameIdPairs = {}
      
      
    -- Get the number of mathematical formulations
    local jsonString = mw.text.jsonEncode(jsonResults)
local totalFormulations = #jsonResults.results.bindings
    -- Decode the JSON string into a Lua table
local data = mw.text.jsonDecode(jsonString)
      
      
     if totalFormulations > 0 then
    -- Get the number of contained entities
local totalContainedEntities = #data.results.bindings
 
     if totalContainedEntities > 0 then
     -- Loop through the bindings
     -- Loop through the bindings
for index = 0, totalFormulations do
for index = 1, totalContainedEntities do
     local item = jsonResults.results.bindings[index]
     local item = data.results.bindings[index]
     local equationLabel = item.Formula.value
     local itemLabel = item.Formula.value
   
         local equationIDURL = item.IDFormula.value
         local equationIDURL = item.IDFormula.value
         local equationID = equationIDURL:match(".*/(.-)$") or equationIDURL -- Extracts the part after the last '/'
         local equationID = equationIDURL:match(".*/(.-)$") or equationIDURL -- Extracts the part after the last '/'
         local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
         local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        table.insert(containedEntities, qualValueWithUrl)
    local equationWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(equationLabel))
        local instances = getInstanceOf(equationID)
        for _, id in ipairs(instances) do
        if(id == "Q6481152") then
        -- if is about a mathematical expression (Q6481152) that is contained
        local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
    local equationWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
       
        local equation = mw.wikibase.getEntity(equationID)
        
        
        local equation = mw.wikibase.getEntity(equationID)
    -- P989 refers to property defining formula  
    -- P989 refers to property defining formula  
    local definingFormula = equation:getBestStatements('P989')
    local definingFormula = equation:getBestStatements('P989')
    if definingFormula and #definingFormula > 0 then
    if definingFormula and #definingFormula > 0 then
    local value = definingFormula[1].mainsnak.datavalue.value
    local value = definingFormula[1].mainsnak.datavalue.value
    mathTag = frame:extensionTag{
    mathTag = frame:extensionTag{
        name = "math",
        name = "math",
        content = value
        content = value
        }
        }
        local qualValue = item.qualValueLabel or item.qualValue or ""
        -- width is set below to 1200px
        local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
        -- the percentage below refer to 40% of 1200px and 60% of 1200px to define width
        local test = "test"
        -- for the first and the second column accordingly
        if qualValue ~= "" then
        table.insert(formulations,  
        table.insert(containedEntities,  
    string.format('| style="width:40%%;" | %s || style="width:60%%;" | %s', equationWithUrl, mathTag))
    string.format('| %s || %s || %s || %s', equationWithUrl, mathTag, qualValueWithUrl, test))
else
    else
table.insert(formulations, "| " .. equationWithUrl)
    table.insert(containedEntities,
end
    string.format('| %s || %s', equationWithUrl, mathTag))
end
else
      local qualValue = item.qualValueLabel or item.qualValue or ""
      local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
      local test = "test"
      if qualValue ~= "" then
local row = "| " .. equationWithUrl .. " || " ..  qualValueWithUrl .. " || " ..  test
table.insert(containedEntities, row)
else
table.insert(containedEntities, "| " .. equationWithUrl)
end
end
    
    
       
        quantitySymbolNameIdPairs = p.extractQuantities(equationID)
        
        
        if type(quantitySymbolNameIdPairs) == "table" then
        quantitySymbolNameIdPairs = p.extractQuantities(equationID)
        -- Accessing the stored pairs
for i, pair in ipairs(quantitySymbolNameIdPairs) do
local pairFirstValue = pair[1]
local pairFirstValue = mw.text.decode(pairFirstValue or "")
local quantitySymbolMathTag = frame:extensionTag{
name = "math",
            content = pairFirstValue
        }
        -- Construct the Portal URL
        local url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
        local numericId = pair[3]:sub(2)  -- remove "Q" to get "6674540"
        local fullUrl = url .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
        
        
            table.insert(formulations, "| " .. quantitySymbolMathTag  ..  " symbol represents "  .. labelWithUrl)
        if type(quantitySymbolNameIdPairs) == "table" then
        -- Accessing the stored pairs
for i, pair in ipairs(quantitySymbolNameIdPairs) do
local pairFirstValue = pair[1]
local pairFirstValue = mw.text.decode(pairFirstValue or "")
local quantitySymbolMathTag = frame:extensionTag{
name = "math",
            content = pairFirstValue
        }
        -- Construct the Portal URL
        local numericId = pair[3]:sub(2)  -- remove "Q" to get "6674540"
        local instances = getInstanceOf(pair[3])
        -- Define a set of allowed IDs for Quantity
local allowedQuantityIds = {
    Q6534245 = true,
    Q6534237 = true,
    }
    local url = ""
        for _, id in ipairs(instances) do
        if allowedQuantityIds[id] then
        -- if the symbol is a quantity kind or a quantity
        -- Construct the Portal URL
        url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
        elseif(id == "Q6481152") then
        -- if is about a mathematical expression (Q6481152) that is contained
        url = "https://portal.mardi4nfdi.de/wiki/Formula:"
        end
        -- go over values of instances
        end
       
        local fullUrl = url .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
       
            table.insert(containedEntities, "| " .. " || ".. quantitySymbolMathTag  ..  " represents "  .. labelWithUrl)
end
table.insert(containedEntities, "| " .. " " )
else
end
elseif(id == "Q68663") then
-- if is about a model (Q68663) that is contained
local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
    local modelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
table.insert(containedEntities, "| " .. modelWithUrl)
elseif(id == "Q6534237") then
-- if is about a quantity (Q6534237) that is contained
local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
local urlRendered = "https://portal.mardi4nfdi.de/wiki/Quantity:" .. numericId
    local quantityWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
   
-- table.insert(containedEntities, "| " .. quantityWithUrl)
local equation = mw.wikibase.getEntity(equationID)
       
    -- P989 refers to property defining formula
    local definingFormula = equation:getBestStatements('P989')
    if definingFormula and #definingFormula > 0 then
    local value = definingFormula[1].mainsnak.datavalue.value
    mathTag = frame:extensionTag{
        name = "math",
        content = value
        }
        local qualValue = item.qualValueLabel or item.qualValue or ""
        local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
        if qualValue ~= "" then
        table.insert(containedEntities,
    string.format('| %s || %s || %s', quantityWithUrl, mathTag, qualValueWithUrl))
    else
    table.insert(containedEntities,
    string.format('| %s || %s', quantityWithUrl, mathTag))
end
else
      local qualValue = item.qualValueLabel or item.qualValue or ""
      local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
if qualValue ~= "" then
local row = "| " .. quantityWithUrl .. " || " .. qualValueWithUrl
    table.insert(containedEntities, row)
-- table.insert(containedEntities, "| " .. quantityWithUrl, qualValue.value )
else
table.insert(containedEntities, "| " .. quantityWithUrl)
end
end
quantitySymbolNameIdPairs = p.extractQuantities(equationID)
       
        if type(quantitySymbolNameIdPairs) == "table" then
        -- Accessing the stored pairs
for i, pair in ipairs(quantitySymbolNameIdPairs) do
local pairFirstValue = pair[1]
local pairFirstValue = mw.text.decode(pairFirstValue or "")
local quantitySymbolMathTag = frame:extensionTag{
name = "math",
            content = pairFirstValue
        }
        -- Construct the Portal URL
        local url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
        local numericId = pair[3]:sub(2)  -- remove "Q" to get "6674540"
        local fullUrl = url .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
       
            table.insert(containedEntities, "| " .. " || ".. quantitySymbolMathTag  ..  " represents "  .. labelWithUrl)
end
table.insert(containedEntities, "| " .. " " )
else
end
-- if is about a quantity (Q6534237) that is contained
end
end
table.insert(formulations, "| " .. " " )
-- Loop through the instances
else
    end
-- Error: extractQuantities did not return a table"
        -- Loop through the bindings
end
end
end


-- Construct the Wikitext table
-- Construct the Wikitext table
     local wikitextTable = [[
     local wikitextTable = [[
{| class="wikitable" style="table-layout: fixed; width: 1200px;"
{| class="wikitable" style="table-layout: auto;"
]] .. table.concat(formulations, "\n|-\n") .. "\n|}"
]] .. table.concat(containedEntities, "\n|-\n") .. "\n|}"
     return wikitextTable
     return wikitextTable
     else  
     else  
Line 262: Line 472:
end
end


-- Function to get specialized Models
function p.getSpecializedModels(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1684: specialized by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
WHERE {
entityId: p:P1684 ?statement .
?statement ps:P1684 ?URL .
?URL rdfs:label ?Label
FILTER(LANG(?Label) = "en")
OPTIONAL {
    ?statement ?qualProp ?qualValue .
    FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))  # only qualifiers
    # Map qualifier property to its property entity
    BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)


function p.getImageWithLegend(frame)
    OPTIONAL {
-- Property ID for the local image
    ?qualPropEntity rdfs:label ?qualPropLabel .
    local pidLocalImage  = "P1640"  
    FILTER(LANG(?qualPropLabel) = "en")
    -- Property ID for the (qualifier) media legend
    }
    local pidMediaLegend = "P401"  
 
    local defaultLegend = "No legend available."
    OPTIONAL {
    ?qualValue rdfs:label ?qualValueLabel .
    FILTER(LANG(?qualValueLabel) = "en")
    }
}
}
ORDER BY ?Label
]]


 
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return "No specialized research fields found"
    end
local specializedModels = {}
    -- Get the number of specialized research fields
local totalSpecModels = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalSpecModels  do
    local item = jsonResults.results.bindings[index]
    if not item.Label.value then
        return "Error: Missing item.Label.value"
    elseif not item.URL.value then
        return "Error: Missing item.URL.value"
    else
    local label = item.Label.value
        local url = item.URL.value
        local numericId = url:match("Q(%d+)")
        local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        local qualValue = item.qualValueLabel or item.qualValue or ""
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        if qualValue ~= "" then
        local qualPropWithUrl = string.format('[%s %s]', tostring(item.qualPropEntity.value), tostring(item.qualPropLabel.value))
        local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
        local row = "| " .. labelWithUrl .. " || " .. qualPropWithUrl .. " || " ..  qualValueWithUrl
    table.insert(specializedModels, row)
        else
        table.insert(specializedModels, "| " .. labelWithUrl)
        end
    end
end
 
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(specializedModels, "\n|-\n") .. "\n|}"
return wikitextTable
 
end
 
-- Function to get model assumptions
function p.getAssumptions(frame)
local entityId = frame.args[1]
local entityId = frame.args[1]
      
      
Line 278: Line 563:
     end
     end
      
      
     -- Attempt to retrieve entity data
     -- Constructing the SPARQL query with dynamic entity entityId
     local entity = mw.wikibase.getEntity(entityId)
    -- P1674: assumes property id
    local imageClaims = entity.claims[pidLocalImage]
     local sparqlQuery = [[
     local imageStrings = {}
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
if imageClaims and type(imageClaims) == "table" then
SELECT ?AssumptionURL ?AssumptionLabel
    local numClaims = #imageClaims
WHERE {
    -- Loop through the image claims
entityId: p:P1674 ?statement.
for index = 1, numClaims do
?statement ps:P1674 ?AssumptionURL.
-- Extract the image filename
?AssumptionURL rdfs:label ?AssumptionLabel.
    local imageFilename = imageClaims[index].mainsnak.datavalue.value
FILTER(LANG(?AssumptionLabel) = "en")
local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
}
-- Add this image line to the list
ORDER BY ?AssumptionLabel
        table.insert(imageStrings, string.format("[[File:%s|thumb|470px|%s]]", imageFilename, imageLegend))
]]
        if index < numClaims then
 
        -- spacer column
 
        table.insert(imageStrings, '&nbsp;')
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return "No computational task found"
     end
local assumptions = {}
    -- Get the number of computational tasks
local totalAssumptions = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalAssumptions  do
    local item = jsonResults.results.bindings[index]
    if not item.AssumptionLabel.value then
        return "Error: Missing item.Label.value"
    elseif not item.AssumptionURL.value then
        return "Error: Missing item.URL.value"
    else
        local label = item.AssumptionLabel.value
        local url = item.AssumptionURL.value
        local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        local ordinal = item.Ordinal and item.Ordinal.value or nil
local prefix = ordinal and (ordinal .. ". ") or ""
table.insert(assumptions, "| " .. prefix .. labelWithUrl)
    end
end
 
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(assumptions, "\n|-\n") .. "\n|}"
return wikitextTable
 
end
 
-- Function to get model discretizations
function p.getDiscretizations(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1656: discretized property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?DiscretizedURL ?DiscretizedLabel
WHERE {
entityId: p:P1656 ?statement.
?statement ps:P1656 ?DiscretizedURL.
?DiscretizedURL rdfs:label ?DiscretizedLabel.
FILTER(LANG(?DiscretizedLabel) = "en")
}
ORDER BY ?DiscretizedLabel
]]
 
 
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return " "
    end
local discretizations = {}
    -- Get the number of discretizations
local totalDiscretizations = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalDiscretizations do
    local item = jsonResults.results.bindings[index]
    if not item.DiscretizedLabel.value then
        return "Error: Missing item.Label.value"
    elseif not item.DiscretizedURL.value then
        return "Error: Missing item.URL.value"
    else
        local label = item.DiscretizedLabel.value
        local url = item.DiscretizedURL.value
        local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
table.insert(discretizations, "| "  .. labelWithUrl)
    end
end
 
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(discretizations, "\n|-\n") .. "\n|}"
return wikitextTable
 
end
 
-- Function to get model approximations
function p.getApproximations(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1655: approximated by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?ApproximatedURL ?ApproximatedLabel
WHERE {
entityId: p:P1655 ?statement.
?statement ps:P1655 ?ApproximatedURL.
?ApproximatedURL rdfs:label ?ApproximatedLabel.
FILTER(LANG(?ApproximatedLabel) = "en")
}
ORDER BY ?ApproximatedLabel
]]
 
 
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return " "
    end
local approximations = {}
    -- Get the number of approximations
local totalApproximations = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalApproximations  do
    local item = jsonResults.results.bindings[index]
    if not item.ApproximatedLabel.value then
        return "Error: Missing item.Label.value"
    elseif not item.ApproximatedURL.value then
        return "Error: Missing item.URL.value"
    else
        local label = item.ApproximatedLabel.value
        local url = item.ApproximatedURL.value
        local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
table.insert(approximations, "| "  .. labelWithUrl)
    end
end
 
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(approximations, "\n|-\n") .. "\n|}"
return wikitextTable
 
end
 
-- Function to get model approximations
function p.getSoftware(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1463: describes a project that uses property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?SoftwareURL ?SoftwareLabel
WHERE {
entityId: p:P1463 ?statement.
?statement ps:P1463 ?SoftwareURL.
?SoftwareURL rdfs:label ?SoftwareLabel.
FILTER(LANG(?SoftwareLabel) = "en")
}
ORDER BY ?SoftwareLabel
]]
 
 
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return " "
    end
local software = {}
    -- Get the number of software items
local totalSoftware = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalSoftware  do
    local item = jsonResults.results.bindings[index]
    if not item.SoftwareLabel.value then
        return "Error: Missing item.Label.value"
    elseif not item.SoftwareURL.value then
        return "Error: Missing item.URL.value"
    else
        local label = item.SoftwareLabel.value
        local url = item.SoftwareURL.value
        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
table.insert(software, "| "  .. labelWithUrl)
    end
end
 
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(software, "\n|-\n") .. "\n|}"
return wikitextTable
 
end
 
 
-- Function to get model approximations
function p.getLinearizedBy(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1657: linearized by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?LinearizedURL ?LinearizedLabel
WHERE {
entityId: p:P1657 ?statement.
?statement ps:P1657 ?LinearizedURL.
?LinearizedURL rdfs:label ?LinearizedLabel.
FILTER(LANG(?LinearizedLabel) = "en")
}
ORDER BY ?LinearizedLabel
]]
 
 
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return " "
    end
local linearizations = {}
    -- Get the number of software items
local totalLlinearizations = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalLlinearizations  do
    local item = jsonResults.results.bindings[index]
    if not item.LinearizedLabel.value then
        return "Error: Missing item.Label.value"
    elseif not item.LinearizedURL.value then
        return "Error: Missing item.URL.value"
    else
        local label = item.LinearizedLabel.value
        local url = item.LinearizedURL.value
        local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
table.insert(linearizations, "| "  .. labelWithUrl)
    end
end
 
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(linearizations, "\n|-\n") .. "\n|}"
return wikitextTable
 
end
 
-- Function to get similar models
function p.getSimilar(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1691: similar to property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?SimilarURL ?SimilarLabel
WHERE {
entityId: p:P1691 ?statement.
?statement ps:P1691 ?SimilarURL.
?SimilarURL rdfs:label ?SimilarLabel.
FILTER(LANG(?SimilarLabel) = "en")
}
ORDER BY ?SimilarLabel
]]
 
 
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return " "
     end
     end
end   
-- Combine all image cells into one row of a wikitable
local similar = {}
local imageTable = '{| class="wikitable"\n| ' .. table.concat(imageStrings, ' || ') .. '\n|}'
    -- Get the number of similar expressions
return imageTable .. "\n\n"
local totalSimilar = #jsonResults.results.bindings
else
-- Loop through the bindings
     return " "
for index = 0, totalSimilar  do
    local item = jsonResults.results.bindings[index]
    if not item.SimilarLabel.value then
        return "Error: Missing item.Label.value"
    elseif not item.SimilarURL.value then
        return "Error: Missing item.URL.value"
    else
        local label = item.SimilarLabel.value
        local url = item.SimilarURL.value
        local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
table.insert(similar, "| " .. labelWithUrl)
     end
end
end


-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(similar, "\n|-\n") .. "\n|}"
return wikitextTable
end
end


return p
return p

Latest revision as of 14:11, 18 November 2025

Documentation for this module may be created at Module:Model/doc

-- Required modules for SPARQL queries and HTML table generation
-- Module for executing SPARQL queries
local sparql = require('SPARQL')
-- MediaWiki library for logging and utilities
local mw = require('mw')
local json = require("mw.text") 


-- Main table to hold all functions
local p = {}



-------------------------------- Local Functions -------------------------------

-- Utility: get all P31 values of an entity
local function getInstanceOf(qid)
    local e = mw.wikibase.getEntityObject(qid)
    local result = {}
    if not e or not e.claims or not e.claims["P31"] then
        return result
    end
    for _, claim in pairs(e.claims["P31"]) do
        local id = claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value.id
        if id then
            table.insert(result, id)
        end
    end
    return result
end
-------------------------------- Local Functions -------------------------------


------------------------------- Helper Functions -------------------------------
function p.convertJsonToTable(jsonResults)
	local resultsTable = {}
	if jsonResults and jsonResults.results and jsonResults.results.bindings then
		local bindings = jsonResults.results.bindings
		for j=0, #bindings do
			local row = {}
			for key, value in pairs(bindings[j]) do
				table.insert(row, value.value)
			end
			table.insert(resultsTable, row)
		end
	end
    return resultsTable
end
------------------------------- Helper Functions -------------------------------


-- Function to get model types
function p.getModelTypes(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: used by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?ModelTypeLabel WHERE {
  entityId: p:P31 ?statement .
  ?statement ps:P31 ?ModelType .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?ModelTypeLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
    end
	
	local modelTypes = {}
    -- Get the number of model types
	local totalModelTypes = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalModelTypes  do
    	local item = jsonResults.results.bindings[index]
    	if item and item.ModelTypeLabel and item.ModelTypeLabel.value then
        	local label = item.ModelTypeLabel.value
        	table.insert(modelTypes, label)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n|-\n| " .. table.concat(modelTypes, " || ") .. "\n|}"
	return wikitextTable

end


-- Function to get Computational Tasks
function p.getComputationalTasks(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P147: used by property id
    -- P146: series ordinal property id
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label (SAMPLE(?StatementOrdinal) AS ?Ordinal)
	WHERE {
		entityId: p:P147 ?statement.
		?statement ps:P147 ?URL.
		OPTIONAL { ?statement pq:P146 ?StatementOrdinal. }
		?URL rdfs:label ?Label.
		FILTER(LANG(?Label) = "en")
	}
	GROUP BY ?URL ?Label
	ORDER BY
		ASC(COALESCE(xsd:integer(?Ordinal), 999999))
		ASC(?Label)
	]]

--	local sparqlQuery = [[
--	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
--		SELECT ?URL ?URLLabel ?nextURL ?nextURLLabel 
--		WHERE {
--		entityId: p:P147 ?statement.
--		?statement ps:P147 ?URL.
--		OPTIONAL { ?statement pq:P146 ?Ordinal. }
--		OPTIONAL { ?statement pq:P581 ?nextURL. }
--		SERVICE wikibase:label { 
--		bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
--		}
--		ORDER BY ASC(xsd:integer(COALESCE(?Ordinal, 9999)))
--	]]



	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No computational task found"
    end
	
	local computationalTasks = {}
    -- Get the number of computational tasks
	local totalCompTasks = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalCompTasks  do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	local ordinal = item.Ordinal and item.Ordinal.value or nil
			local prefix = ordinal and (ordinal .. ". ") or ""
			table.insert(computationalTasks, "| " .. prefix .. labelWithUrl)
			-- if item.nextURL then
			-- 	local nexturl = item.nextURL.value
			-- 	local nextnumericId = nexturl:match("Q(%d+)")
			-- 	local nextLabel = item.nextURLLabel.value
			-- 	local nexturlRendered = "https://portal.mardi4nfdi.de/wiki/Task:" .. nextnumericId
			-- 	local nextLabelWithUrl = string.format('[%s %s]', tostring(nexturlRendered), tostring(nextLabel))
			-- 	table.insert(computationalTasks, "| " .. labelWithUrl .. " followed by " .. nextLabelWithUrl)
-- 			else
-- 				table.insert(computationalTasks, "| " .. labelWithUrl)
-- 			end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(computationalTasks, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get Formulations with Quantities
function p.getFormulationsWithQuantities(frame)
	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end

    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1560: contains property id
    -- P989: defining formula property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?Formula ?defining_formulation ?IDFormula ?qualValueLabel ?qualValue
	WHERE {
		# full statement node for P1560
		entityId: p:P1560 ?statement .
		?statement ps:P1560 ?IDFormula .
		FILTER(LANG(?qualValueLabel) = "en")
  
		OPTIONAL { 
    		?IDFormula rdfs:label ?Formula .
    		FILTER(LANG(?Formula) = "en")
		}
		OPTIONAL { ?IDFormula wdt:P989 ?defining_formulation . }

		# qualifiers on this statement
		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers
    		OPTIONAL { 
    		?qualProp rdfs:label ?qualPropLabel .
    		FILTER(LANG(?qualPropLabel) = "en")
    		}
    	OPTIONAL { 
    		?qualValue rdfs:label ?qualValueLabel .
    		FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Formula
]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	
		-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
		return "\"No mathematical expressions found.\""
    end
	
	-- local resultTable = p.convertJsonToTable(jsonResults)
	-- return "<pre>" .. mw.text.nowiki(json.jsonEncode(resultTable)) .. "</pre>"
    -- local jsonString = mw.text.jsonEncode(jsonResults)
    -- return "<pre>" .. mw.text.nowiki(jsonString) .. "</pre>"
	return p.extractDefiningFormulationsWithQuantities(jsonResults)

end


-- Function to extract Formulations with Quantities 
function p.extractDefiningFormulationsWithQuantities(jsonResults)
	local frame = mw.getCurrentFrame()
	-- Table to store contained entities
    local containedEntities = {}
    -- Table to store quantity symbol and name id 
    local quantitySymbolNameIdPairs = {}
    
    local jsonString = mw.text.jsonEncode(jsonResults)
    -- Decode the JSON string into a Lua table
	local data = mw.text.jsonDecode(jsonString)
    
    -- Get the number of contained entities
	local totalContainedEntities = #data.results.bindings

    if totalContainedEntities > 0 then
    	-- Loop through the bindings
		for index = 1, totalContainedEntities  do
    		local item = data.results.bindings[index]
    		local itemLabel = item.Formula.value
    		
        	local equationIDURL = item.IDFormula.value
        	local equationID = equationIDURL:match(".*/(.-)$") or equationIDURL -- Extracts the part after the last '/'
        	local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        table.insert(containedEntities, qualValueWithUrl)
					
        	local instances = getInstanceOf(equationID)
        	for _, id in ipairs(instances) do
        		if(id == "Q6481152") then
        			-- if is about a mathematical expression (Q6481152) that is contained
        			local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
    				local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
    				local equationWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
        			
        			local equation = mw.wikibase.getEntity(equationID)
        	
		    		-- P989 refers to property defining formula 
		    		local definingFormula = equation:getBestStatements('P989')
		    		if definingFormula and #definingFormula > 0 then
    					local value = definingFormula[1].mainsnak.datavalue.value
    					mathTag = frame:extensionTag{
	        				name = "math",
	         				content = value
        				}
	        			local qualValue = item.qualValueLabel or item.qualValue or ""
	        			local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        			local test = "test"
	        			if qualValue ~= "" then
	        				table.insert(containedEntities, 
    						string.format('| %s || %s || %s || %s', equationWithUrl, mathTag, qualValueWithUrl, test))
    					else
    						table.insert(containedEntities, 
    						string.format('| %s || %s', equationWithUrl, mathTag))
						end	
					else
	       				local qualValue = item.qualValueLabel or item.qualValue or ""
	       				local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	       				local test = "test"
	       				if qualValue ~= "" then
							local row = "| " .. equationWithUrl .. " || " ..  qualValueWithUrl .. " || " ..  test
							table.insert(containedEntities, row)
						else
							table.insert(containedEntities, "| " .. equationWithUrl)
						end
					end
   
        	
        			quantitySymbolNameIdPairs = p.extractQuantities(equationID)
        	
        			if type(quantitySymbolNameIdPairs) == "table" then
        				-- Accessing the stored pairs
						for i, pair in ipairs(quantitySymbolNameIdPairs) do
							local pairFirstValue = pair[1]
							local pairFirstValue = mw.text.decode(pairFirstValue or "")
							local quantitySymbolMathTag = frame:extensionTag{
								name = "math",
            					content = pairFirstValue
        					}
        					-- Construct the Portal URL
        					local numericId = pair[3]:sub(2)  -- remove "Q" to get "6674540"
        					local instances = getInstanceOf(pair[3])
        					-- Define a set of allowed IDs for Quantity
							local allowedQuantityIds = {
    						Q6534245 = true,
    						Q6534237 = true,
    						}
    						local url = ""
        					for _, id in ipairs(instances) do
        						if allowedQuantityIds[id] then
        							-- if the symbol is a quantity kind or a quantity
        							-- Construct the Portal URL
        							url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
        						elseif(id == "Q6481152") then
        							-- if is about a mathematical expression (Q6481152) that is contained
        							url = "https://portal.mardi4nfdi.de/wiki/Formula:"
        						end
        					-- go over values of instances
        					end
        					
        					local fullUrl = url .. numericId
        					local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
        	
            				table.insert(containedEntities, "| " .. " || ".. quantitySymbolMathTag   ..  " represents "  .. labelWithUrl)
						end
					table.insert(containedEntities, "| " .. " " )
					else
					end
				elseif(id == "Q68663") then
					-- if is about a model (Q68663) that is contained
					local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
					local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
    				local modelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
					table.insert(containedEntities, "| " .. modelWithUrl)
				
				elseif(id == "Q6534237") then
					-- if is about a quantity (Q6534237) that is contained
					local numericId = equationID:sub(2)  -- remove "Q" to get "6674540"
					local urlRendered = "https://portal.mardi4nfdi.de/wiki/Quantity:" .. numericId
    				local quantityWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(itemLabel))
    				
					-- table.insert(containedEntities, "| " .. quantityWithUrl)
					local equation = mw.wikibase.getEntity(equationID)
        	
		    		-- P989 refers to property defining formula 
		    		local definingFormula = equation:getBestStatements('P989')
		    		if definingFormula and #definingFormula > 0 then
    					local value = definingFormula[1].mainsnak.datavalue.value
    					mathTag = frame:extensionTag{
	        				name = "math",
	         				content = value
        				}
	        			local qualValue = item.qualValueLabel or item.qualValue or ""
	        			local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        			if qualValue ~= "" then
	        				table.insert(containedEntities, 
    						string.format('| %s || %s || %s', quantityWithUrl, mathTag, qualValueWithUrl))
    					else
    						table.insert(containedEntities, 
    						string.format('| %s || %s', quantityWithUrl, mathTag))
						end	
					else
	       				local qualValue = item.qualValueLabel or item.qualValue or ""
	       				local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
						if qualValue ~= "" then
							local row = "| " .. quantityWithUrl .. " || " .. qualValueWithUrl 
    						table.insert(containedEntities, row)
							-- table.insert(containedEntities, "| " .. quantityWithUrl, qualValue.value )
						else
							table.insert(containedEntities, "| " .. quantityWithUrl)
						end
					end
					quantitySymbolNameIdPairs = p.extractQuantities(equationID)
        	
        			if type(quantitySymbolNameIdPairs) == "table" then
        				-- Accessing the stored pairs
						for i, pair in ipairs(quantitySymbolNameIdPairs) do
							local pairFirstValue = pair[1]
							local pairFirstValue = mw.text.decode(pairFirstValue or "")
							local quantitySymbolMathTag = frame:extensionTag{
								name = "math",
            					content = pairFirstValue
        					}
        					-- Construct the Portal URL
        					local url = "https://portal.mardi4nfdi.de/wiki/Quantity:"
        					local numericId = pair[3]:sub(2)  -- remove "Q" to get "6674540"
        					local fullUrl = url .. numericId
        					local labelWithUrl = string.format('[%s %s]', tostring(fullUrl), tostring(pair[2]))
        	
            				table.insert(containedEntities, "| " .. " || ".. quantitySymbolMathTag   ..  " represents "  .. labelWithUrl)
						end
					table.insert(containedEntities, "| " .. " " )
					else
					end
				-- if is about a quantity (Q6534237) that is contained
				end
			-- Loop through the instances	
    		end
        -- Loop through the bindings
		end

		-- Construct the Wikitext table
    	local wikitextTable = [[
{| class="wikitable" style="table-layout: auto;"
]] .. table.concat(containedEntities, "\n|-\n") .. "\n|}"
    	return wikitextTable
    else 
    	return "No mathematical expressions found."
    end
end


function p.extractQuantities(qid)
	-- Property ID for in defining formula 
    local pidInDefiningFormula  = "P983"
    -- Property ID for the (qualifier) symbol represents
    local pidSymbolRepresents = "P984"   

    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(qid)
    if not entity or not entity.claims[pidInDefiningFormula] then
        return "No formulation found"
    end
    
    
    local inDefiningFormulaClaims = entity.claims[pidInDefiningFormula]
    local count = 0
    -- Table to store pairs of quantity symbol and quantity name
    local quantitySymbolNameIdPairs = {}
	for _ in pairs(inDefiningFormulaClaims or {}) do
    	count = count + 1
    	-- Get the quantity symbol
    	local quantitySymbol = inDefiningFormulaClaims[count].mainsnak.datavalue.value
    	if not quantitySymbol then
        	return "No valid symbol found"
    	end
    	quantity = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.text
        quantityId = inDefiningFormulaClaims[count].qualifiers[pidSymbolRepresents][1].datavalue.value.id
	    local quantityName = mw.wikibase.label(quantityId)
	    -- Insert pair into the table
	    table.insert(quantitySymbolNameIdPairs, {quantitySymbol, quantityName, quantityId})
    end
    return quantitySymbolNameIdPairs
end

-- Function to get specialized Models
function p.getSpecializedModels(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1684: specialized by property id
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
	WHERE {
		entityId: p:P1684 ?statement .
		?statement ps:P1684 ?URL .
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")

		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers

	    	# Map qualifier property to its property entity
    		BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)

	    	OPTIONAL {
    			?qualPropEntity rdfs:label ?qualPropLabel .
    			FILTER(LANG(?qualPropLabel) = "en")
    		}

    		OPTIONAL {
    			?qualValue rdfs:label ?qualValueLabel .
    			FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized research fields found"
    end
	
	local specializedModels = {}
    -- Get the number of specialized research fields
	local totalSpecModels = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSpecModels  do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local qualValue = item.qualValueLabel or item.qualValue or ""
	        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
	        if qualValue ~= "" then
	        	local qualPropWithUrl = string.format('[%s %s]', tostring(item.qualPropEntity.value), tostring(item.qualPropLabel.value))
	        	local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        	local row = "| " .. labelWithUrl .. " || " .. qualPropWithUrl .. " || " ..  qualValueWithUrl
    			table.insert(specializedModels, row)
	        else
        		table.insert(specializedModels, "| " .. labelWithUrl)
        	end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(specializedModels, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model assumptions
function p.getAssumptions(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1674: assumes property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?AssumptionURL ?AssumptionLabel
	WHERE {
		entityId: p:P1674 ?statement.
		?statement ps:P1674 ?AssumptionURL.
		?AssumptionURL rdfs:label ?AssumptionLabel.
		FILTER(LANG(?AssumptionLabel) = "en")
	}
	ORDER BY ?AssumptionLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No computational task found"
    end
	
	local assumptions = {}
    -- Get the number of computational tasks
	local totalAssumptions = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalAssumptions  do
    	local item = jsonResults.results.bindings[index]
    	if not item.AssumptionLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.AssumptionURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.AssumptionLabel.value
        	local url = item.AssumptionURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	local ordinal = item.Ordinal and item.Ordinal.value or nil
			local prefix = ordinal and (ordinal .. ". ") or ""
			table.insert(assumptions, "| " .. prefix .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(assumptions, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model discretizations
function p.getDiscretizations(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1656: discretized property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?DiscretizedURL ?DiscretizedLabel
	WHERE {
		entityId: p:P1656 ?statement.
		?statement ps:P1656 ?DiscretizedURL.
		?DiscretizedURL rdfs:label ?DiscretizedLabel.
		FILTER(LANG(?DiscretizedLabel) = "en")
	}
	ORDER BY ?DiscretizedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local discretizations = {}
    -- Get the number of discretizations
	local totalDiscretizations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalDiscretizations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.DiscretizedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.DiscretizedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.DiscretizedLabel.value
        	local url = item.DiscretizedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(discretizations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(discretizations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model approximations
function p.getApproximations(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1655: approximated by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?ApproximatedURL ?ApproximatedLabel
	WHERE {
		entityId: p:P1655 ?statement.
		?statement ps:P1655 ?ApproximatedURL.
		?ApproximatedURL rdfs:label ?ApproximatedLabel.
		FILTER(LANG(?ApproximatedLabel) = "en")
	}
	ORDER BY ?ApproximatedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local approximations = {}
    -- Get the number of approximations
	local totalApproximations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalApproximations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.ApproximatedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.ApproximatedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.ApproximatedLabel.value
        	local url = item.ApproximatedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(approximations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(approximations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get model approximations
function p.getSoftware(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1463: describes a project that uses property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?SoftwareURL ?SoftwareLabel
	WHERE {
		entityId: p:P1463 ?statement.
		?statement ps:P1463 ?SoftwareURL.
		?SoftwareURL rdfs:label ?SoftwareLabel.
		FILTER(LANG(?SoftwareLabel) = "en")
	}
	ORDER BY ?SoftwareLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local software = {}
    -- Get the number of software items
	local totalSoftware = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSoftware  do
    	local item = jsonResults.results.bindings[index]
    	if not item.SoftwareLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.SoftwareURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.SoftwareLabel.value
        	local url = item.SoftwareURL.value
        	local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
			table.insert(software, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(software, "\n|-\n") .. "\n|}"
	return wikitextTable

end


-- Function to get model approximations
function p.getLinearizedBy(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1657: linearized by property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?LinearizedURL ?LinearizedLabel
	WHERE {
		entityId: p:P1657 ?statement.
		?statement ps:P1657 ?LinearizedURL.
		?LinearizedURL rdfs:label ?LinearizedLabel.
		FILTER(LANG(?LinearizedLabel) = "en")
	}
	ORDER BY ?LinearizedLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local linearizations = {}
    -- Get the number of software items
	local totalLlinearizations = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalLlinearizations  do
    	local item = jsonResults.results.bindings[index]
    	if not item.LinearizedLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.LinearizedURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.LinearizedLabel.value
        	local url = item.LinearizedURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(linearizations, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(linearizations, "\n|-\n") .. "\n|}"
	return wikitextTable

end

-- Function to get similar models
function p.getSimilar(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P1691: similar to property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?SimilarURL ?SimilarLabel
	WHERE {
		entityId: p:P1691 ?statement.
		?statement ps:P1691 ?SimilarURL.
		?SimilarURL rdfs:label ?SimilarLabel.
		FILTER(LANG(?SimilarLabel) = "en")
	}
	ORDER BY ?SimilarLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return " "
    end
	
	local similar = {}
    -- Get the number of similar expressions
	local totalSimilar = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSimilar  do
    	local item = jsonResults.results.bindings[index]
    	if not item.SimilarLabel.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.SimilarURL.value then
        	return "Error: Missing item.URL.value"
    	else
        	local label = item.SimilarLabel.value
        	local url = item.SimilarURL.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
			table.insert(similar, "| "  .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(similar, "\n|-\n") .. "\n|}"
	return wikitextTable
	
end


return p