You can write a custom C routine for APS to calculate operation duration for selected operations. The system calls your custom calculation routine if the operation's Custom Planner Rule field is selected.
The standard operation calculation routine is ol_opercalc. By default, it returns the value -1.0, which signals the algorithm to use the standard (that is, non-custom) calculation to determine the operation's duration. The C code for this routine is shown below.
#include "ol_api.h" double ol_opercalc(opercalc) opercalc_s* opercalc; { return(-1.0); }
The input to ol_opercalc is a pointer to an opercalc_s structure. As shown below, this structure contains information used to calculate operation duration.
/*------------------------------------------------------------------------*/ typedef struct attid_struct /*------------------------------------------------------------------------*/ { char attid[MAX_OLXFSTR+1]; char attvalue[MAX_OLXFSTR+1]; } attid_s; /*------------------------------------------------------------------------*/ typedef struct reslist_struct /*------------------------------------------------------------------------*/ { char resource[MAX_OLXFSTR+1]; char category[MAX_OLXFSTR+1]; double catbufpre; double catbufpost; long numresattids; attid_s** resattidlist; } reslist_s; /*------------------------------------------------------------------------*/ typedef struct opercalc_struct /*------------------------------------------------------------------------*/ { char operation[MAX_OLXFSTR+1]; char order[MAX_OLXFSTR+1]; char part[MAX_OLXFSTR+1]; double quantity; char startwindow[14]; char endwindow[14]; long oprflags; double oprsetup; double oprcycle; double oprbufpre; double oprbufpost; long oprovltype; double oprovlvalue; long matltag; long numresources; reslist_s** resourcelist; long numoprattids; attid_s** oprattidlist; long numordattids; attid_s** ordattidlist; long numprtattids; attid_s** prtattidlist; } opercalc_s;
There are two types of output from ol_opercalc:
When the algorithm passes these parameters to ol_opercalc, the parameters contain the user-specified values from the database. You can modify them within ol_opercalc before returning them back to the algorithm. If they are modified, the system will respond as follows:
You can enable operation overlapping through the original database value or by modifying oprovltype. If it is enabled, and if oprsetup is modified and/or the ol_opercalc return value denotes a different oprcycle value is in effect (considering setting of the operation's Fixed Schedule Hours and Custom Planner Rule fields), the system will recalculate the overlap offset for this operation.
When you write your routine, make sure the return value is of type double. The return value must represent the total required operation duration (in hours), for the specified number of parts using the specified resources, during the time interval available for the production.
The following example ol_opercalc routine determines the operation time for a particular resource.
#include "ol_api.h" double ol_opercalc(opercalc) opercalc_s* opercalc; { FILE* log_fp; int i,j; double dTime; log_fp = fopen("d:\\opercalc50.txt","a"); fprintf(log_fp, "\nopercalc: oper=>%s<\n", opercalc->operation ); fflush(log_fp); fprintf(log_fp, "opercalc: numoprattids=%d\n", opercalc->numoprattids ); fflush(log_fp); for (i=0;i<opercalc->numoprattids;i++) { fprintf(log_fp, "opercalc: opr attid =>%s<\n" "opercalc: opr attvalue=>%s<\n", opercalc->oprattidlist[i]->attid, opercalc->oprattidlist[i]->attvalue ); fflush(log_fp); } fprintf(log_fp, "opercalc: order=>%s<\n", opercalc->order ); fflush(log_fp); fprintf(log_fp, "opercalc: numordattids=%d\n", opercalc->numordattids ); fflush(log_fp); for (i=0;i<opercalc->numordattids;i++) { fprintf(log_fp, "opercalc: ord attid =>%s<\n" "opercalc: ord attvalue=>%s<\n", opercalc->ordattidlist[i]->attid, opercalc->ordattidlist[i]->attvalue ); fflush(log_fp); } fprintf(log_fp, "opercalc: part=>%s<\n", opercalc->part ); fflush(log_fp); fprintf(log_fp, "opercalc: numprtattids=%d\n", opercalc->numprtattids ); fflush(log_fp); for (i=0;i<opercalc->numprtattids;i++) { fprintf(log_fp, "opercalc: prt attid =>%s<\n" "opercalc: prt attvalue=>%s<\n", opercalc->prtattidlist[i]->attid, opercalc->prtattidlist[i]->attvalue ); fflush(log_fp); } fprintf(log_fp, "opercalc: quantity=%f\n", opercalc->quantity ); fflush(log_fp); fprintf(log_fp, "opercalc: start=>%s<\n", opercalc->startwindow ); fflush(log_fp); fprintf(log_fp, "opercalc: end=>%s<\n", opercalc->endwindow ); fflush(log_fp); fprintf(log_fp, "opercalc: oprflags=%d\n", opercalc->oprflags ); fflush(log_fp); fprintf(log_fp, "opercalc: oprsetup=%f\n", opercalc->oprsetup ); fflush(log_fp); fprintf(log_fp, "opercalc: oprcycle=%f\n", opercalc->oprcycle ); fflush(log_fp); fprintf(log_fp, "opercalc: oprbufpre=%f\n", opercalc->oprbufpre ); fflush(log_fp); fprintf(log_fp, "opercalc: oprbufpost=%f\n", opercalc->oprbufpost ); fflush(log_fp); fprintf(log_fp, "opercalc: oprovltype=%d\n", opercalc->oprovltype ); fflush(log_fp); fprintf(log_fp, "opercalc: oprovlvalue=%f\n", opercalc->oprovlvalue ); fflush(log_fp); fprintf(log_fp, "opercalc: numresources=%d\n", opercalc->numresources ); fflush(log_fp); for (i=0;i<opercalc->numresources;i++) { fprintf(log_fp, "opercalc: resource=>%s<\n", opercalc->resourcelist[i]->resource ); fflush(log_fp); fprintf(log_fp, "opercalc: category=>%s<\n", opercalc->resourcelist[i]->category ); fflush(log_fp); fprintf(log_fp, "opercalc: catbufpre=%f\n", opercalc->resourcelist[i]->catbufpre ); fflush(log_fp); fprintf(log_fp, "opercalc: catbufpost=%f\n", opercalc->resourcelist[i]->catbufpost ); fflush(log_fp); fprintf(log_fp, "opercalc: numresattids=%d\n", opercalc->resourcelist[i]->numresattids ); fflush(log_fp); for (j=0;j<opercalc->resourcelist[i]->numresattids;j++) { fprintf(log_fp, "opercalc: res attid =>%s<\n" "opercalc: res attvalue=>%s<\n", opercalc->resourcelist[i]->resattidlist[j]->attid, opercalc->resourcelist[i]->resattidlist[j]->attvalue ); fflush(log_fp); } } dTime = -1.0; if ( (!strcmp(opercalc->part,"SA-50910")) && (!strcmp(opercalc->operation, "SA-50910 SA-5.20")) && (!strcmp(opercalc->resourcelist[0]->resource,"PNT10.1")) ) { if ( opercalc->oprflags == 2 ) { fprintf(log_fp, "opercalc: per cycle\n"); fflush(log_fp); if ( opercalc->quantity > 10.0 ) { opercalc->oprsetup = 0.15; fprintf(log_fp, "opercalc: changing oprsetup\n"); opercalc->oprcycle = 0.25; fprintf(log_fp, "opercalc: changing oprcycle\n"); opercalc->oprovltype = 1; fprintf(log_fp, "opercalc: changing oprovltype\n"); opercalc->oprovlvalue = opercalc->quantity / 2; fprintf(log_fp, "opercalc: changing oprovlvalue\n"); opercalc->oprbufpre = opercalc->quantity / 2; fprintf(log_fp, "opercalc: changing oprbufpre to qty/2=%f\n", opercalc->oprbufpre); opercalc->oprbufpost = opercalc->quantity / 4; fprintf(log_fp, "opercalc: changing oprbufpost to qty/4=%f\n", opercalc->oprbufpost); // dTime = opercalc->oprcycle * opercalc->quantity; fflush(log_fp); } } else { fprintf(log_fp, "opercalc: per load\n"); fflush(log_fp); dTime = 1.0; /* opercalc->oprsetup = 0.0; opercalc->oprcycle = 0.1; opercalc->oprovltype = 1; opercalc->oprovlvalue = 3.0; */ } } fprintf(log_fp, "opercalc: dTime = >%f<\n", dTime ); fflush(log_fp); fclose(log_fp); return(dTime); }
The SyteLine setup program installs the standard version of the opercalc50.dll into your \winnt\system32 directory. This dll contains a dummy version of the ol_opercalc routine. You must create a customized opercalc50.dll containing your custom ol_opercalc routine that will be used instead of the standard opercalc50.dll.
To create this dll, follow these steps:
;-------------------------------------------------- ; OPERCALC50.DEF DLL library module definition file ;-------------------------------------------------- LIBRARY OPERCALC50 INITINSTANCE DESCRIPTION 'SyteAPS V5.0 OperCalc', Copyright © 2010 Infor. All rights reserved. www.infor.com' ; EXPORTS ol_opercalc = _ol_opercalc@4 _ol_opercalc = _ol_opercalc@4
You must compile the code with the following code generation options to match those expected by the system's executable call:
NOTE: When you delete an APS Project, all of its folders and files are deleted, including the opercalc50.dll. Therefore, be careful never to put your Visual C++ source code (as mentioned in step 1) in the project folder.
When APS runs, it uses your custom routine only if the operation's JOBSTEP.STEPTMRL field is set to 2 (Custom Planner Rule selected, Fixed Schedule Hours contains a value) or 3 (Custom Planner Rule selected, Fixed Schedule Hours blank or 0). An operation with a STEPTMRL value of 2 uses fixed cycle time; a value of 3 uses per-piece cycle time.
If the operation's Custom Planner Rule is cleared, the system will not call the custom ol_opercalc routine.