/* * Copyright (c) 2013 Patrick Meyer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.itemanalysis.jmetrik.stats.irt.equating; import com.itemanalysis.jmetrik.dao.DatabaseAccessObject; import com.itemanalysis.jmetrik.sql.DataTableName; import com.itemanalysis.jmetrik.sql.DatabaseName; import com.itemanalysis.jmetrik.sql.VariableTableName; import com.itemanalysis.jmetrik.stats.irt.linking.DbItemParameterSet; import com.itemanalysis.jmetrik.stats.irt.linking.DbThetaDistribution; import com.itemanalysis.jmetrik.swing.JmetrikTextFile; import com.itemanalysis.psychometrics.data.DataType; import com.itemanalysis.psychometrics.data.ItemType; import com.itemanalysis.psychometrics.data.VariableAttributes; import com.itemanalysis.psychometrics.data.VariableName; import com.itemanalysis.psychometrics.distribution.DistributionApproximation; import com.itemanalysis.psychometrics.irt.equating.IrtTrueScoreEquating; import com.itemanalysis.psychometrics.irt.model.ItemResponseModel; import com.itemanalysis.psychometrics.tools.StopWatch; import org.apache.log4j.Logger; import javax.swing.*; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.*; public class IrtEquatingAnalysis extends SwingWorker<String, String> { private IrtEquatingCommand command = null; private Connection conn = null; private JmetrikTextFile textFile = null; private Throwable theException = null; private StopWatch sw = null; private LinkedHashMap<String, ItemResponseModel> irmX = null; private LinkedHashMap<String, ItemResponseModel> irmY = null; private DistributionApproximation xDistribution = null; private DistributionApproximation yDistribution = null; private DataTableName tableNameItemsX = null; private DataTableName tableNameItemsY = null; private ArrayList<VariableName> itemsFormX = null; private ArrayList<VariableName> itemsFormY = null; private DatabaseName outputDbName = null; private DataTableName outputTable = null; private DataTableName tableNamePersonsX = null; private VariableName thetaNameX = null; private VariableName weightNameX = null; private boolean hasWeightX = false; private VariableAttributes newTheta = null; private DataTableName tableNamePersonsY = null; private VariableName thetaNameY = null; private VariableName weightNameY = null; private boolean hasWeightY = false; private boolean logisticScale = true; private boolean trueScoreMethod = true; private boolean newItemTableCreated = false; private boolean createOutputTable = false; private DatabaseAccessObject dao = null; private DatabaseName dbName = null; IrtTrueScoreEquating irtTrueScoreEquating = null; static Logger logger = Logger.getLogger("jmetrik-logger"); static Logger scriptLogger = Logger.getLogger("jmetrik-script-logger"); public IrtEquatingAnalysis(Connection conn, DatabaseAccessObject dao, IrtEquatingCommand command, JmetrikTextFile textFile){ this.conn = conn; this.dao = dao; this.command = command; this.textFile = textFile; itemsFormX = new ArrayList<VariableName>(); itemsFormY = new ArrayList<VariableName>(); } public void processCommand()throws IllegalArgumentException{ String xDbName = command.getPairedOptionList("xitem").getStringAt("db"); String xTable = command.getPairedOptionList("xitem").getStringAt("table"); tableNameItemsX = new DataTableName(xTable); dbName = new DatabaseName(xDbName);//assumes that same database is used for all parameter String yDbName = command.getPairedOptionList("yitem").getStringAt("db"); //same as dbName String yTable = command.getPairedOptionList("yitem").getStringAt("table"); tableNameItemsY = new DataTableName(yTable); ArrayList<String> fX = command.getFreeOptionList("xvar").getString(); itemsFormX = new ArrayList<VariableName>(); for(String s : fX){ itemsFormX.add(new VariableName(s)); } ArrayList<String> fY = command.getFreeOptionList("yvar").getString(); for(String s : fY){ itemsFormY.add(new VariableName(s)); } if(command.getPairedOptionList("xability").hasValue() && command.getPairedOptionList("yability").hasValue()){ String xPersonTable = command.getPairedOptionList("xability").getStringAt("table"); String xPersonTheta = command.getPairedOptionList("xability").getStringAt("theta"); String xPersonWeight = command.getPairedOptionList("xability").getStringAt("weight"); if(xPersonTable!=null && !xPersonTable.equals("null")){ tableNamePersonsX = new DataTableName(xPersonTable); thetaNameX = new VariableName(xPersonTheta); weightNameX = new VariableName(xPersonWeight); if(!xPersonWeight.trim().equals("")){ hasWeightX = true; } } String yPersonTable = command.getPairedOptionList("yability").getStringAt("table"); String yPersonTheta = command.getPairedOptionList("yability").getStringAt("theta"); String yPersonWeight = command.getPairedOptionList("yability").getStringAt("weight"); if(yPersonTable!=null && !yPersonTable.equals("null")){ tableNamePersonsY = new DataTableName(yPersonTable); thetaNameY = new VariableName(yPersonTheta); weightNameY = new VariableName(yPersonWeight); if(!yPersonWeight.trim().equals("")){ hasWeightY = true; } } } logisticScale = command.getSelectOneOption("scale").isValueSelected("logistic"); trueScoreMethod = command.getSelectOneOption("method").isValueSelected("true"); if(command.getPairedOptionList("output").hasValue()){ String oDb = command.getPairedOptionList("output").getStringAt("db"); String oT = command.getPairedOptionList("output").getStringAt("table"); outputDbName = new DatabaseName(oDb); outputTable = new DataTableName(oT); createOutputTable = true; } } private void getItemParameters() throws SQLException { DbItemParameterSet itemParameterSet = new DbItemParameterSet(); irmX = itemParameterSet.getItemParameters(conn, tableNameItemsX, itemsFormX, logisticScale); irmY = itemParameterSet.getItemParameters(conn, tableNameItemsY, itemsFormY, logisticScale); } public void getThetaDistributions()throws IllegalArgumentException, SQLException{ DbThetaDistribution dist = new DbThetaDistribution(); xDistribution = dist.getDistribution(conn, tableNamePersonsX, thetaNameX, weightNameX, hasWeightX); yDistribution = dist.getDistribution(conn, tableNamePersonsY, thetaNameY, weightNameY, hasWeightY); } private String conductEquating(){ irtTrueScoreEquating = new IrtTrueScoreEquating(irmX, irmY); irtTrueScoreEquating.equateScores(); return irtTrueScoreEquating.printResults(); } private void saveOutput()throws SQLException{ PreparedStatement pstmt = null; try{ conn.setAutoCommit(false);//start transaction outputTable = dao.getUniqueTableName(conn, outputTable.toString()); VariableTableName variableTableName = new VariableTableName(outputTable.toString()); VariableAttributes score = new VariableAttributes("score", "Score", ItemType.NOT_ITEM, DataType.DOUBLE, 1, ""); VariableAttributes theta = new VariableAttributes("theta", "Form X theta", ItemType.NOT_ITEM, DataType.DOUBLE, 2, ""); VariableAttributes yequiv = new VariableAttributes("yequiv", "Y Equivalent of score", ItemType.NOT_ITEM, DataType.DOUBLE, 3, ""); VariableAttributes conv = new VariableAttributes("conv", "Newton-Rhapson convergence status", ItemType.NOT_ITEM, DataType.STRING, 4, ""); ArrayList<VariableAttributes> variables = new ArrayList(); variables.add(score); variables.add(theta); variables.add(yequiv); variables.add(conv); dao.createTables(conn, outputTable, variableTableName, variables); double[] scorePoints = irtTrueScoreEquating.getScorePoints(); double[] xtheta = irtTrueScoreEquating.getFormXThetaValues(); double[] yeq = irtTrueScoreEquating.getYEquivalentTrueScores(); char[] status = irtTrueScoreEquating.getStatus(); String query = "INSERT INTO " + outputTable.getNameForDatabase() + " VALUES(?, ?, ?, ?)"; pstmt = conn.prepareStatement(query); for(int i=0;i<scorePoints.length;i++){ pstmt.setDouble(1,scorePoints[i]); pstmt.setDouble(2,xtheta[i]); pstmt.setDouble(3,yeq[i]); pstmt.setString(4,String.valueOf(status[i]).toString()); pstmt.executeUpdate(); } newItemTableCreated = true; conn.commit();//end transaction }catch(SQLException ex){ conn.rollback(); conn.setAutoCommit(true); throw ex; }finally{ conn.setAutoCommit(true); if(pstmt!=null) pstmt.close(); } } public void publishHeader()throws IllegalArgumentException{ StringBuilder header = new StringBuilder(); Formatter f = new Formatter(header); String s1 = String.format("%1$tB %1$te, %1$tY %tT", Calendar.getInstance()); int len = 38+Double.valueOf(Math.floor(Double.valueOf(s1.length()).doubleValue()/2.0)).intValue(); String dString = ""; dString = command.getDataString(); f.format("%45s", "IRT SCORE EQUATING"); f.format("%n"); f.format("%" + len + "s", s1); f.format("%n"); f.format("%n"); f.format("%-" + dString.length() + "s", dString); f.format("%n"); publish(f.toString()); } @Override protected void process(List<String> chunks){ for(String s : chunks){ textFile.append(s + "\n"); } } @Override protected String doInBackground(){ sw = new StopWatch(); this.firePropertyChange("status", "", "Running IRT Score Equating..."); this.firePropertyChange("progress-ind-on", null, null); try{ processCommand(); publishHeader(); getItemParameters(); publish(conductEquating()); if(createOutputTable) saveOutput(); firePropertyChange("status", "", "Done: " + sw.getElapsedTime()); firePropertyChange("progress-off", null, null); //make statusbar progress not visible }catch(Throwable t){ logger.fatal(t.getMessage(), t); theException = t; } return sw.getElapsedTime(); } @Override protected void done(){ try{ if(theException!=null){ logger.fatal(theException.getMessage(), theException); firePropertyChange("error", "", "Error - Check log for details."); }else{ if(newItemTableCreated){ this.firePropertyChange("table-added", "", outputTable);//will add to list } } textFile.addText(get()); textFile.setCaretPosition(0); scriptLogger.info(command.paste()); }catch(Exception ex){ logger.fatal(ex.getMessage(), ex); firePropertyChange("error", "", "Error - Check log for details."); } } }