Home Dynamics Projects Dynamics Blogs Microsoft Watch Stem cells

 

 

Job Scheduling - Hard link-Advance stuff

Let us play around this code to increase our understanding.

Let us fix a problem in job scheduling that should never be fixed.

Now you must be wondering if the problem should never be fixed then why bother writing code to fix the problem? My answer is to understand job scheduling. There is no way anyone is going to pick up job scheduling without modifying existing code and make it work differently.

So here we go

A.      The problem

During job scheduling, planned production orders in coverage get scheduled backwards from the requirement date. If no capacity is found then the planned orders are scheduled forward from today’s date (till the capacity is found).

Let us say we have operation 10 and 20. 10 is with infinite capacity and 20 is with finite capacity. During forward scheduling Opr 10 will get scheduled on today’s date (since it is running with infinite capacity) but operation 20 will get scheduled whenever the system finds free capacity. This will create a huge time gap between the schedules of operations 10 and 20. Further if this particular item is at level 0, all subsequent orders for BOM components are going to be created with a requirement date of today’s date. This will drastically increase the stock (including WIP).

This happens very frequently if someone is using job scheduling with finite capacity during the master planning runs. There are multiple reasons for this which are outside the scope of this blog.

 

B.      Why this problem should not be fixed?

You should never run master planning with job scheduling. Master planning scheduling is indicative in nature, giving you approximate demand for machine hours during a time period. Job scheduling is scheduling down to an exact second and you do not need this accuracy during master planning.

I know, I know you can come up with a lot of scenarios where you are forced to run job scheduling with master planning. But if you take a deep breath and really think hard then you can find answers to all your problems even with operations scheduling.

 

C.      The fix

So the basic concept is as follows: if the scheduling is being run as part of master planning and if direction is forward and the operation has been scheduled with in-finite capacity then the operation must be scheduled as close as possible to the next operation. (Something like using hard-links).

Say we have operation 10 and 20 (infinite) 30 finite 40 infinite and 50 finite. In this case 10 and 20 are going to be scheduled close to operation 30. Though 40 is with infinite capacity we are not going to stick it to Operation 50. Why not operation 40? …think..think…think

Fortunately, there is no need to write any complicated code. We are just going to re-use the concept of hard-links to achieve what we need.

Before going any further you should also look at my job scheduling blog 

You must also take a look at my previous blog about hard-links 

Understanding the above two blogs is of vital importance to understanding the code we are going to write.

a.       To begin with we need a method to get the “next operation number” for any operation. So you need to create the following method on WrkCtrRouteData class

OprNum oprNumNextForced(OprNum _oprNum)

{

    OprNum  oprNumSave;

    int     i;

    for (i = 1; i <= qty ; i++)

    {

        if (oprNum[i] == _oprNum)

            break;

        oprNumSave = oprNum[i];

    } 

    return oprNumSave;

}

 

In case you are wondering why this method returns the next operation number then check how the route data is loaded (wrkCtrRouteDate_req->Load()). Check the index that is being used to sort the data, open table browser for ReqRoute and check the value for a column called ‘level’.

b.      We also need a method to set all links to hard. Create the following method on WrkCtrJobLinkData

void setAllLinkTypeHard()

{

    int i;

    for (i = 1; i <= qty; i++)

        linkType[i] = SchedJobLinkType::Hard;

}

 

c.       Now we start modifying WrkCtrScheduleJobs_Detail

Create two class level variables

    Set         OprNumLoadedSet;

    boolean     stopSticking;

 

Next edit WrkCtrScheduleJobs – ScheduleLimitedCapacity and put the following code line immediately after if (this.mustBeScheduledLimited())

 stopSticking = true;

So if the value of this variable is true then we know that at least one job was scheduled with finite capacity and we should not stick the operations together.

And finally the fun part, create the following method on WrkCtrScheduleJobs_Detail

void stickItUp()

{

    OprNum  oprNum;

    ;

   If (stopSticking)

      return; // at least one job was scheduled with finite capacity

  If (!parmSchedule.reqTransExtern() )

     Return;// the ‘sticking’ code shuld get executed only during master planning.  

  if (parmSchedule.schedDirection() != SchedDirection::Forward)

      return; // the ‘sticking’ code should be executed only during forward scheduling.

  if (! routeData.rec_OprNumNext())

      return; //If there is no next operation then there is nothing to stick together.

  If ( jobLinkData.num() != jobLinkData.qty() )

      Return;//num represents the current line and qty represents the total number of lines. Num != qty  means we are not on the last line of the operation. i.e. setup, process etc.

 

   jobLinkData.setAllLinkTypeHard(); //set all links to hard

   routeData.savePosition(); //save current position

   routeData.find(routeData.oprNum2Idx(jobLinkData.rec_OprNum())); //go to the operation

   routeData.rec_LinkType(SchedJobLinkType::Hard);// set the link to hard

   routeData.restorePosition(); // go to the saved position

   oprNum = routeData.rec_OprNum();

   routeData.savePosition();

   jobData.savePosition();

   jobLinkData.savePosition();

  routeData.find(routeData.oprNum2Idx(routeData.oprNumNextForced(jobLinkData.rec_OprNum())));

 

    if (!oprNumLoadedSet)

          oprNumLoadedSet = new Set(Types::Integer);

 

     if (!oprNumLoadedSet.in(routeData.rec_OprNum())) //load an operation only once

      {

            jobLinkData.load(); //this actually loads the details of the next operation.

            oprNumLoadedSet.add(routeData.rec_OprNum());

            routeData.rec_OprNumSched(oprNum);//in our example  operation 20 is being scheduled as a

                                                                                    //part of operation 10. Record this information

       }

 

        routeData.restorePosition();

        jobData.restorePosition();

        jobLinkData.restorePosition();

 

}

 

Now the last thing to do is to call this method from WrkCtrScheduleJobs_Detail->schedule.

Put the following line immediately after conflictMove = this.ScheduleLimitedCapacity(true);

    this.stickItUp();

 

Now comes the fun part which is testing*s*. I have not tested this code at all but I think it should work. For the purpose of testing, comment out the following lines.

  If (!parmSchedule.reqTransExtern() )

     Return;// the ‘sticking’ code shuld get executed only during master planning.

 

Next, create a production order that has a route containing 10, 20 with infinite capacity and 30 with finite capacity and schedule forwards from today’s date. Check if 10 and 20 are scheduled along side operation 30. Do not forget to add primary, secondary operations to all route lines and make sure that each line uses setup, process, queue time etc etc.

I would recommend setting a route where each line runs for a day. Create two productin orders which are exactly the same. Schedule first production order and then schedule second production order that will create the discussed problem. Next uncomment the above code lines to see if they actually work.

Best of luck! Remember this is only for understanding the job scheduling code. In real life, better way is to run master planning with operations scheduling.

 

Send mail to harry@systomatics.com with questions or comments about this web site.
Disclaimer: I am working with Microsoft Business Solutions. The code on this site may or may not be related to my official duties with Microsoft. I do not claim in any expertise in modules represented on this website. Essentially there is just one person doing functional specifications (in head), design specifications (in head), coding and some testing. There is no way the project on this site will be free of bugs. The projects are intended as guidelines and may god help you if you decide to implement the projects without making any changes. If you implement any project resulting into data corruption or anything like that then do not even think of suing me because a. I have already warned you and b. I don't have any money. I may or may not respond to your emails about supporting the project. I may or may not upgrade the projects to the next service pack / version.