Module:Model: Difference between revisions

From MaRDI portal
No edit summary
No edit summary
Line 41: Line 41:
     -- P31: used by property id
     -- P31: used by property id
     local sparqlQuery = [[
     local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?ModelTypeLabel WHERE {
SELECT  ?ModelTypeLabel WHERE {
   entityId: p:P31 ?statement .
   entityId: p:P31 ?statement .
Line 54: Line 55:
-- 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 computational task found"
     end
     end

Revision as of 14:06, 16 September 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 = {}


------------------------------- 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 ?Ordinal
	WHERE {
		entityId: p:P147 ?statement.
		?statement ps:P147 ?URL.
		OPTIONAL { ?statement pq:P146 ?Ordinal. }
		?URL rdfs:label ?Label.
	}
	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)))
--	]]



	-- 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 
	WHERE {
      entityId: wdt:P1560 ?IDFormula.
      OPTIONAL { ?IDFormula  rdfs:label ?Formula. }
      OPTIONAL { ?IDFormula  wdt:P989 ?defining_formulation. }
	}
    ]]

	-- 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 formulations
    local formulations = {}
    -- 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 mathematical formulations
	local totalFormulations = #data.results.bindings

    if totalFormulations > 0 then
    	-- Loop through the bindings
		for index = 1, totalFormulations  do
    		local item = data.results.bindings[index]
    		local equationLabel = item.Formula.value
        	local equationIDURL = item.IDFormula.value
        	local equationID = equationIDURL:match(".*/(.-)$") or equationIDURL -- Extracts the part after the last '/'
        	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(equationLabel))
        	
        	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
        		}
	        	-- width is set below to 1200px
	        	-- the percentage below refer to 40% of 1200px and 60% of 1200px to define width 
	        	-- for the first and the second column accordingly
	        	table.insert(formulations, 
    string.format('| style="width:40%%;" | %s || style="width:60%%;" | %s', equationWithUrl, mathTag))
			else
				table.insert(formulations, "| " .. equationWithUrl)
			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(formulations, "| " .. quantitySymbolMathTag   ..  " symbol represents "  .. labelWithUrl)
				end
			table.insert(formulations, "| " .. " " )
			else
				-- Error: extractQuantities did not return a table"
			end
		end

		-- Construct the Wikitext table
    	local wikitextTable = [[
{| class="wikitable" style="table-layout: fixed; width: 1200px;"
]] .. table.concat(formulations, "\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 Research 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  
	WHERE {
		entityId: wdt:P1684 ?URL.
		?URL rdfs:label ?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 labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	table.insert(specializedModels, "| " .. labelWithUrl)
    	end
	end

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

end

return p